Fajnie, że Go ma Duration
typ - posiadanie wyraźnie zdefiniowanych jednostek może zapobiec problemom w świecie rzeczywistym.
A ze względu na surowe reguły Go, nie można pomnożyć Czas trwania przez liczbę całkowitą - musisz użyć rzutowania, aby pomnożyć popularne typy.
/*
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'
}
Oficjalna dokumentacja pokazuje, stosując metodę nr 1:
Aby przekonwertować liczbę całkowitą jednostek na czas trwania, pomnóż:
seconds := 10
fmt.Print(time.Duration(seconds)*time.Second) // prints 10s
Ale oczywiście pomnożenie czasu trwania przez czas trwania nie powinno dać czasu trwania - na pierwszy rzut oka to nonsens. W tym przypadku produkuje się 5 milisekund razy 5 milisekund 6h56m40s
. Próba kwadratu 5 sekund powoduje przepełnienie (i nawet nie zostanie skompilowane, jeśli zostanie wykonane ze stałymi).
Nawiasem mówiąc, int64
reprezentacja Duration
w nanosekundach „ogranicza największy reprezentatywny czas trwania do około 290 lat” , a to wskazuje, że Duration
podobnie int64
, jest traktowane jako wartość podpisana: (1<<(64-1))/(1e9*60*60*24*365.25) ~= 292
i dokładnie tak jest realizowane:
// 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
Ponieważ wiemy, że podstawową reprezentacją Duration
jest int64
wykonywanie rzutowania pomiędzy int64
i Duration
jest rozsądnym NO-OP - wymagane tylko w celu spełnienia reguł językowych dotyczących typów miksowania i nie ma to wpływu na kolejną operację mnożenia.
Jeśli nie podoba ci się casting ze względów czystości, zakop go w wywołaniu funkcji, jak pokazałem powyżej.
rand.Seed(time.Now().Unix())