¿Cómo multiplicar la duración por entero?

284

Para probar goroutines concurrentes, agregué una línea a una función para hacer que regrese un tiempo aleatorio (hasta un segundo)

time.Sleep(rand.Int31n(1000) * time.Millisecond)

Sin embargo, cuando compilé, recibí este error

. \ crawler.go: 49: operación no válida: rand.Int31n (1000) * time.Millisecond (tipos no coincidentes int32 y time.Duration)

¿Algunas ideas? ¿Cómo puedo multiplicar una duración?

Coronel Panic
fuente

Respuestas:

430

int32y time.Durationson de diferentes tipos. Necesita convertir el int32a a time.Duration, como time.Sleep(time.Duration(rand.Int31n(1000)) * time.Millisecond).

mna
fuente
55
Gracias que funcionó. También aprendí acerca de sembrar el generador de números aleatoriosrand.Seed(time.Now().Unix())
Coronel Panic
44
Por lo que sé, ¿cómo funciona lo siguiente? time.Sleep(time.Second * 2)
Ishan Khare
59
Funciona porque las constantes tienen un tipo adaptativo, en función de cómo se usan. Vea esta publicación de blog de Rob Pike que lo explica en detalle: blog.golang.org/constants
mna
28
Esta es una de esas cosas raras debido a su sistema de tipo simplista (falta de sobrecarga del operador en este caso): debe convertir la multiplicación a Duration* Duration= Duration, en lugar de la original, que en realidad tiene más sentido: Duration* int= Duration.
Timmmm
14
Bueno, la sobrecarga del operador o la conversión numérica implícita permitirían que esto funcione. Creo que tenían razón al dejar fuera la conversión numérica implícita. Después de mirar hacia atrás, esto int64(...) * Durationtiene mucho más sentido que lanzar Duration, lo cual es solo una violación básica de cómo deberían funcionar las unidades. Lamentablemente eso no funciona. Realmente tienes que hacer lo Duration * Durationque es horrible.
Timmmm
59

Tienes que enviarlo a un formato correcto Playground.

yourTime := rand.Int31n(1000)
time.Sleep(time.Duration(yourTime) * time.Millisecond)

Si verificará la documentación para dormir , verá que requiere una func Sleep(d Duration)duración como parámetro. Tu rand.Int31n regresa int32.

La línea del ejemplo funciona ( time.Sleep(100 * time.Millisecond)) porque el compilador es lo suficientemente inteligente como para comprender que aquí su constante 100 significa una duración. Pero si pasa una variable, debe lanzarla.

Salvador Dalí
fuente
16

En Go, puede multiplicar variables del mismo tipo, por lo que debe tener ambas partes de la expresión del mismo tipo.

Lo más simple que puedes hacer es lanzar un número entero a la duración antes de multiplicar, pero eso violaría la semántica de la unidad. ¿Cuál sería la multiplicación de la duración por la duración en términos de unidades?

Prefiero convertir el tiempo. Milisegundos a un int64, y luego multiplicarlo por el número de milisegundos, luego emitir a tiempo. Duración:

time.Duration(int64(time.Millisecond) * int64(rand.Int31n(1000)))

De esta manera, se puede decir que cualquier parte de la expresión tiene un valor significativo de acuerdo con su tipo. int64(time.Millisecond)parte es solo un valor adimensional: el número de unidades de tiempo más pequeñas en el valor original.

Si camina por un camino un poco más simple:

time.Duration(rand.Int31n(1000)) * time.Millisecond

La parte izquierda de la multiplicación no tiene sentido, un valor de tipo "tiempo. Duración", que contiene algo irrelevante para su tipo:

numberOfMilliseconds := 100
// just can't come up with a name for following:
someLHS := time.Duration(numberOfMilliseconds)
fmt.Println(someLHS)
fmt.Println(someLHS*time.Millisecond)

Y no se trata solo de semántica, hay una funcionalidad real asociada con los tipos. Este código imprime:

100ns
100ms

Curiosamente, el ejemplo de código aquí usa el código más simple, con la misma semántica engañosa de conversión de Duración: https://golang.org/pkg/time/#Duration

segundos: = 10

fmt.Print (time.Duration (segundos) * time.Second) // imprime 10s

George Polevoy
fuente
5

Es bueno que Go tenga un Durationtipo: tener unidades definidas explícitamente puede prevenir problemas del mundo real.

Y debido a las estrictas reglas de tipo de Go, no puedes multiplicar una Duración por un entero; debes usar un yeso para multiplicar los tipos comunes.

/*
MultiplyDuration Hide semantically invalid duration math behind a function
*/
func MultiplyDuration(factor int64, d time.Duration) time.Duration {
    return time.Duration(factor) * d        // method 1 -- multiply in 'Duration'
 // return time.Duration(factor * int64(d)) // method 2 -- multiply in 'int64'
}

La documentación oficial demuestra el uso del método 1:

Para convertir un número entero de unidades a una Duración, multiplique:

seconds := 10
fmt.Print(time.Duration(seconds)*time.Second) // prints 10s

Pero, por supuesto, multiplicar una duración por una duración no debería producir una duración, eso no tiene sentido a primera vista. Caso en cuestión, produce 5 milisegundos por 5 milisegundos 6h56m40s. Intentar cuadrar 5 segundos resulta en un desbordamiento (y ni siquiera se compilará si se hace con constantes).

Por cierto, la int64representación Durationen nanosegundos "limita la mayor duración representable a aproximadamente 290 años" , y esto indica que Duration, como int64, se trata como un valor con signo: (1<<(64-1))/(1e9*60*60*24*365.25) ~= 292y así es exactamente como se implementa:

// A Duration represents the elapsed time between two instants
// as an int64 nanosecond count. The representation limits the
// largest representable duration to approximately 290 years.
type Duration int64

Entonces, porque sabemos que la representación subyacente de Durationes un int64, realizando el reparto entre int64yDuration es un NO-OP sensible, requerido solo para satisfacer las reglas del lenguaje sobre la mezcla de tipos, y no tiene ningún efecto en la operación de multiplicación posterior.

Si no le gusta el casting por razones de pureza, entiérrelo en una llamada a la función como he mostrado anteriormente.

sin bar
fuente
"multiplicar como / con tipos comunes".
nobar
Discusión similar relacionada con la división en la respuesta (incorrecta) aquí .
nobar
-3

Para la multiplicación de variable a tiempo. Segundo usando el siguiente código

    oneHr:=3600
    addOneHrDuration :=time.Duration(oneHr)
    addOneHrCurrTime := time.Now().Add(addOneHrDuration*time.Second)
delroy.santos
fuente
Esta no es una buena forma de usar las time.Durationvariables de Go . Usted nombra su variable addOneHrDurationde tiempo time.Durationpero luego procede a configurarla en 3600 ns, no en una hora. A time.Durationtiene unidades base de nanosegundos. Para obtener realmente una duración de una hora, puede hacer algo como: const oneHourDuration = 60 * time.Hour(o 3600 * time.Secondo time.Hour).
Dave C