Comment multiplier la durée par un entier?

287

Pour tester des goroutines simultanées, j'ai ajouté une ligne à une fonction pour qu'elle prenne un temps aléatoire pour revenir (jusqu'à une seconde)

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

Cependant, quand j'ai compilé, j'ai eu cette erreur

. \ crawler.go: 49: opération non valide: rand.Int31n (1000) * time.Millisecond (types incompatibles int32 et time.Duration)

Des idées? Comment puis-je multiplier une durée?

Colonel Panic
la source

Réponses:

434

int32et time.Durationsont de types différents. Vous devez convertir le fichier int32en a time.Duration, tel que time.Sleep(time.Duration(rand.Int31n(1000)) * time.Millisecond).

mna
la source
5
Merci qui a fonctionné. J'ai également appris comment amorcer le générateur de nombres aléatoiresrand.Seed(time.Now().Unix())
Colonel Panic
44
juste pour ma connaissance, comment ça marche alors? time.Sleep(time.Second * 2)
Ishan Khare
61
Cela fonctionne parce que les constantes ont un type adaptatif, basé sur la façon dont elles sont utilisées. Voir cet article de blog de Rob Pike qui l'explique en détail: blog.golang.org/constants
mna
28
C'est l'une de ces choses étranges en raison de son système de type simpliste (manque de surcharge de l'opérateur dans ce cas) - vous devez convertir la multiplication en Duration* Duration= Duration, au lieu de l'original qui a en fait plus de sens: Duration* int= Duration.
Timmmm
14
Eh bien, la surcharge de l'opérateur ou la conversion numérique implicite laisserait cela fonctionner. Je pense qu'ils avaient raison de laisser de côté la conversion numérique implicite. Après avoir repensé à cela, cela a int64(...) * Durationbeaucoup plus de sens que de lancer Duration, ce qui n'est qu'une violation de base du fonctionnement des unités. Malheureusement, cela ne fonctionne pas. Vous devez vraiment faire ce Duration * Durationqui est horrible.
Timmmm
62

Vous devez le convertir dans un format correct Playground.

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

Si vous vérifiez la documentation pour le sommeil , vous voyez qu'elle nécessite la func Sleep(d Duration)durée comme paramètre. Votre rand.Int31n revient int32.

La ligne de l'exemple fonctionne ( time.Sleep(100 * time.Millisecond)) car le compilateur est suffisamment intelligent pour comprendre qu'ici votre constante 100 signifie une durée. Mais si vous passez une variable, vous devez la transtyper.

Salvador Dali
la source
16

Dans Go, vous pouvez multiplier les variables du même type, vous devez donc avoir les deux parties de l'expression du même type.

La chose la plus simple que vous puissiez faire est de convertir un entier en durée avant de le multiplier, mais cela violerait la sémantique des unités. Quelle serait la multiplication de la durée par la durée en terme d'unités?

Je préfère convertir time.Millisecond en int64, puis le multiplier par le nombre de millisecondes, puis transtypé en time.

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

De cette façon, n'importe quelle partie de l'expression peut être considérée comme ayant une valeur significative selon son type. int64(time.Millisecond)partie est juste une valeur sans dimension - le nombre de plus petites unités de temps dans la valeur d'origine.

Si vous suivez un chemin un peu plus simple:

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

La partie gauche de la multiplication est un non-sens - une valeur de type "time.Duration", contenant quelque chose de non pertinent pour son type:

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

Et ce n'est pas seulement de la sémantique, il y a des fonctionnalités réelles associées aux types. Ce code imprime:

100ns
100ms

Fait intéressant, l'exemple de code ici utilise le code le plus simple, avec la même sémantique trompeuse de conversion de durée: https://golang.org/pkg/time/#Duration

secondes: = 10

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

George Polevoy
la source
5

C'est bien que Go ait un Durationtype - avoir des unités explicitement définies peut éviter des problèmes du monde réel.

Et en raison des règles de type strictes de Go, vous ne pouvez pas multiplier une durée par un entier - vous devez utiliser un cast pour multiplier les types communs.

/*
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 documentation officielle montre l'utilisation de la méthode # 1:

Pour convertir un nombre entier d'unités en une durée, multipliez:

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

Mais, bien sûr, multiplier une durée par une durée ne devrait pas produire une durée - c'est absurde à première vue. Par exemple, 5 millisecondes multipliées par 5 millisecondes 6h56m40s. Tenter de mettre au carré 5 secondes entraîne un débordement (et ne sera même pas compilé s'il est fait avec des constantes).

Soit dit en passant, la int64représentation Durationen nanosecondes "limite la plus grande durée représentable à environ 290 ans" , et cela indique que Duration, comme int64, est traité comme une valeur signée:, (1<<(64-1))/(1e9*60*60*24*365.25) ~= 292et c'est exactement comme cela qu'il est mis en œuvre:

// 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

Donc, parce que nous savons que la représentation sous-jacente de Durationest un int64, effectuant la conversion entre int64et Durationest un NO-OP sensible - requis uniquement pour satisfaire les règles de langage sur les types de mélange, et cela n'a aucun effet sur l'opération de multiplication suivante.

Si vous n'aimez pas le casting pour des raisons de pureté, enterrez-le dans un appel de fonction comme je l'ai montré ci-dessus.

nobar
la source
msgstr "multiplier comme / avec des types communs".
nobar
Une discussion similaire liée à la division à la (mauvaise) réponse ici .
nobar
-3

Pour la multiplication de la variable en temps, la seconde en utilisant le code suivant

    oneHr:=3600
    addOneHrDuration :=time.Duration(oneHr)
    addOneHrCurrTime := time.Now().Add(addOneHrDuration*time.Second)
delroy.santos
la source
Ce n'est pas un bon moyen d'utiliser les time.Durationvariables de Go . Vous nommez votre variable addOneHrDurationde temps, time.Durationpuis procédez à la définir à 3600 ns et non à une heure. Un time.Durationarrive d'avoir des unités de base de nanosecondes. Pour obtenir une durée d'une heure, vous pouvez faire quelque chose comme: const oneHourDuration = 60 * time.Hour(ou 3600 * time.Secondou time.Hour).
Dave C