Aby przetestować współbieżne goroutine, dodałem wiersz do funkcji, aby powrót zajął losowo (do jednej sekundy)
time.Sleep(rand.Int31n(1000) * time.Millisecond)
Jednak kiedy skompilowałem, dostałem ten błąd
. \ crawler.go: 49: niepoprawna operacja: rand.Int31n (1000) * time.Millisecond (niedopasowane typy int32 i time.Duration)
Jakieś pomysły? Jak mogę pomnożyć czas trwania?
rand.Seed(time.Now().Unix())
time.Sleep(time.Second * 2)
Duration
*Duration
=Duration
, zamiast oryginalnego, co w rzeczywistości ma większy sens:Duration
*int
=Duration
.int64(...) * Duration
ma to o wiele większy sens niż rzucanieDuration
, co jest po prostu podstawowym naruszeniem zasad działania jednostek. Niestety to nie działa. Naprawdę musisz zrobić,Duration * Duration
co jest okropne.Musisz rzucić go na właściwy format Playground.
Jeśli sprawdzisz dokumentację dotyczącą snu , zobaczysz, że wymaga ona
func Sleep(d Duration)
czasu trwania jako parametru. Twój rand.Int31n powracaint32
.Wiersz z przykładu działa (
time.Sleep(100 * time.Millisecond)
), ponieważ kompilator jest wystarczająco inteligentny, aby zrozumieć, że tutaj stała 100 oznacza czas trwania. Ale jeśli podasz zmienną, powinieneś ją rzucić.źródło
W Go możesz pomnożyć zmienne tego samego typu, więc musisz mieć obie części wyrażenia tego samego typu.
Najprostszą rzeczą, jaką możesz zrobić, jest wyrzucenie liczby całkowitej na czas trwania przed pomnożeniem, ale byłoby to sprzeczne z semantyką jednostki. Jakie byłoby pomnożenie czasu trwania przez czas trwania w jednostkach?
Wolałbym przeliczyć czas. Milisekunda na int64, a następnie pomnożyć go przez liczbę milisekund, a następnie rzutować na czas.
W ten sposób można powiedzieć, że dowolna część wyrażenia ma znaczącą wartość w zależności od jej typu.
int64(time.Millisecond)
część jest po prostu wartością bezwymiarową - liczbą najmniejszych jednostek czasu w pierwotnej wartości.Jeśli idziesz nieco prostszą ścieżką:
Lewa część mnożenia to nonsens - wartość typu „time.Duration”, zawierająca coś nieistotnego dla jej typu:
I to nie tylko semantyka, istnieje rzeczywista funkcjonalność związana z typami. Ten kod drukuje:
Co ciekawe, w przykładowym kodzie zastosowano tutaj najprostszy kod z tą samą wprowadzającą w błąd semantyką konwersji czasu trwania: https://golang.org/pkg/time/#Duration
źródło
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.
Oficjalna dokumentacja pokazuje, stosując metodę nr 1:
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
reprezentacjaDuration
w nanosekundach „ogranicza największy reprezentatywny czas trwania do około 290 lat” , a to wskazuje, żeDuration
podobnieint64
, jest traktowane jako wartość podpisana:(1<<(64-1))/(1e9*60*60*24*365.25) ~= 292
i dokładnie tak jest realizowane:Ponieważ wiemy, że podstawową reprezentacją
Duration
jestint64
wykonywanie rzutowania pomiędzyint64
iDuration
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.
źródło
Do pomnożenia zmiennej na czas. Następnie użyj następującego kodu
źródło
time.Duration
zmiennych Go . Nazwij swoją zmiennąaddOneHrDuration
czasu,time.Duration
a następnie ustaw ją na 3600 ns, a nie na godzinę.time.Duration
Zdarza mieć bazowe jednostki nanosekund. Aby faktycznie uzyskać godzinę, możesz zrobić coś takiego:const oneHourDuration = 60 * time.Hour
(lub3600 * time.Second
lubtime.Hour
).