Jak pomnożyć czas trwania przez liczbę całkowitą?


284

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?

Odpowiedzi:


431

int32i time.Durationsą różnymi typami. Trzeba przekonwertować int32do time.Duration, takich jak time.Sleep(time.Duration(rand.Int31n(1000)) * time.Millisecond).


5
Dzięki, że zadziałało. Dowiedziałem się również o uruchomieniu generatora liczb losowychrand.Seed(time.Now().Unix())
pułkowniku Panic

44
dla mojej wiedzy, jak działają następujące rzeczy? time.Sleep(time.Second * 2)
Ishan Khare,

59
Działa, ponieważ stałe mają typ adaptacyjny, w zależności od sposobu ich użycia. Zobacz ten post na blogu Roba Pike'a, który szczegółowo to wyjaśnia: blog.golang.org/constants
mna

28
Jest to jedna z tych dziwnych rzeczy ze względu na jej uproszczony system typów (w tym przypadku brak przeciążenia operatora) - musisz rzucić mnożenie na Duration* Duration= Duration, zamiast oryginalnego, co w rzeczywistości ma większy sens: Duration* int= Duration.
Timmmm

14
Cóż, albo przeciążenie operatora, albo niejawna konwersja numeryczna pozwoliłoby na to. Wydaje mi się, że mieli rację, pomijając ukrytą konwersję numeryczną. Patrząc wstecz na to, int64(...) * Durationma to o wiele większy sens niż rzucanie Duration, co jest po prostu podstawowym naruszeniem zasad działania jednostek. Niestety to nie działa. Naprawdę musisz zrobić, Duration * Durationco jest okropne.
Timmmm

59

Musisz rzucić go na właściwy format Playground.

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

Jeśli sprawdzisz dokumentację dotyczącą snu , zobaczysz, że wymaga ona func Sleep(d Duration)czasu trwania jako parametru. Twój rand.Int31n powraca int32.

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ć.


16

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.

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

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ą:

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

Lewa część mnożenia to nonsens - wartość typu „time.Duration”, zawierająca coś nieistotnego dla jej typu:

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

I to nie tylko semantyka, istnieje rzeczywista funkcjonalność związana z typami. Ten kod drukuje:

100ns
100ms

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

sekund: = 10

fmt.Print (time.Duration (sekundy) * time.Second) // drukuje 10s


5

Fajnie, że Go ma Durationtyp - 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, int64reprezentacja Durationw nanosekundach „ogranicza największy reprezentatywny czas trwania do około 290 lat” , a to wskazuje, że Durationpodobnie int64, jest traktowane jako wartość podpisana: (1<<(64-1))/(1e9*60*60*24*365.25) ~= 292i 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ą Durationjest int64wykonywanie rzutowania pomiędzy int64i Durationjest 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.


„pomnóż jako / z typowymi typami”.
nobar

Podobna dyskusja związana z podziałem przy (złej) odpowiedzi tutaj .
nobar

-3

Do pomnożenia zmiennej na czas. Następnie użyj następującego kodu

    oneHr:=3600
    addOneHrDuration :=time.Duration(oneHr)
    addOneHrCurrTime := time.Now().Add(addOneHrDuration*time.Second)

To nie jest dobry sposób na użycie time.Durationzmiennych Go . Nazwij swoją zmienną addOneHrDurationczasu, time.Durationa następnie ustaw ją na 3600 ns, a nie na godzinę. time.DurationZdarza mieć bazowe jednostki nanosekund. Aby faktycznie uzyskać godzinę, możesz zrobić coś takiego: const oneHourDuration = 60 * time.Hour(lub 3600 * time.Secondlub time.Hour).
Dave C
Korzystając z naszej strony potwierdzasz, że przeczytałeś(-aś) i rozumiesz nasze zasady używania plików cookie i zasady ochrony prywatności.
Licensed under cc by-sa 3.0 with attribution required.