507 Stimmen

Wie multipliziere ich die Dauer mit einer Ganzzahl?

Um gleichzeitig laufende Goroutinen zu testen, habe ich einer Funktion eine Zeile hinzugefügt, die zufällige Zeit benötigt, um zurückzukehren (bis zu einer Sekunde)

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

Aber als ich kompilierte, bekam ich diesen Fehler

.\crawler.go:49: ungültige Operation: rand.Int31n(1000) * time.Millisecond (nicht übereinstimmende Typen int32 und time.Duration)

Irgendwelche Ideen? Wie kann ich eine Dauer multiplizieren?

760voto

mna Punkte 22009

int32 und time.Duration sind unterschiedliche Typen. Du musst das int32 in eine time.Duration umwandeln:

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

91voto

Salvador Dali Punkte 197375

Sie müssen es in das richtige Format umwandeln <a href="https://play.golang.org/p/AN7glnjcs0" rel="noreferrer">Playground</a>.

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

Wenn Sie die Dokumentation für Sleep überprüfen, sehen Sie, dass sie eine func Sleep(d Duration) Dauer als Parameter benötigt. Ihr rand.Int31n gibt int32 zurück.

Die Zeile aus dem Beispiel funktioniert (time.Sleep(100 * time.Millisecond)), weil der Compiler intelligent genug ist zu verstehen, dass hier Ihre Konstante 100 eine Dauer bedeutet. Aber wenn Sie eine Variable übergeben, sollten Sie es umwandeln.

27voto

George Polevoy Punkte 7073

In Go kann man Variablen vom gleichen Typ multiplizieren, daher müssen beide Teile des Ausdrucks den gleichen Typ haben.

Das Einfachste, was man tun kann, ist, eine Ganzzahl in eine Dauer umzuwandeln, bevor man sie multipliziert, aber das würde gegen die Einheitssystematik verstoßen. Was wäre die Multiplikation von Dauer mit Dauer in Bezug auf Einheiten?

Ich würde eher time.Millisecond in ein int64 umwandeln und es dann mit der Anzahl von Millisekunden multiplizieren und dann in time.Duration umwandeln:

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

Auf diese Weise kann gesagt werden, dass jeder Teil des Ausdrucks einen sinnvollen Wert gemäß seines Typs hat. Der Teil int64(time.Millisecond) ist nur ein dimensionsloser Wert - die Anzahl der kleinsten Zeiteinheiten im ursprünglichen Wert.

Wenn man einen etwas einfacheren Weg geht:

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

Der linke Teil der Multiplikation ergibt keinen Sinn - ein Wert vom Typ "time.Duration", der etwas enthält, das nicht relevant für seinen Typ ist:

numberOfMilliseconds := 100
// kann einfach keinen Namen für das Folgende finden:
someLHS := time.Duration(numberOfMilliseconds)
fmt.Println(someLHS)
fmt.Println(someLHS*time.Millisecond)

Und es handelt sich nicht nur um Semantik, sondern um tatsächliche Funktionalität, die mit den Typen verbunden ist. Dieser Code gibt aus:

100ns
100ms

Interessanterweise verwendet das Codesample hier den einfachsten Code, mit der gleichen irreführenden Semantik der Dauerumwandlung: https://golang.org/pkg/time/#Duration

seconds := 10

fmt.Print(time.Duration(seconds)*time.Second) // gibt 10s aus

15voto

Brent Bradburn Punkte 45995

Es ist schön, dass Go einen Dauer Typ hat - durch explizit definierte Einheiten können reale Probleme vermieden werden.

Und aufgrund der strengen Typregeln von Go kannst du eine Dauer nicht mit einem Integer multiplizieren - du musst einen Cast verwenden, um gemeinsame Typen zu multiplizieren.

/*
MultiplyDuration Verberge semantisch ungültige Dauer-Mathematik hinter einer Funktion
*/
func MultiplyDuration(factor int64, dauer time.Duration) time.Duration {
    return time.Duration(factor) * dauer        // Methode 1 -- multipliziere in 'Dauer'
 // return time.Duration(factor * int64(dauer)) // Methode 2 -- multipliziere in 'int64'
}

Die offizielle Dokumentation demonstriert die Verwendung von Methode #1:

Um eine ganze Anzahl von Einheiten in eine Dauer umzuwandeln, multipliziere:

sekunden := 10
fmt.Print(time.Duration(sekunden)*time.Second) // gibt 10s aus

Aber natürlich sollte die Multiplikation einer Dauer mit einer Dauer keine Dauer ergeben - das ist von vornherein unsinnig. Zum Beispiel ergibt 5 Millisekunden mal 5 Millisekunden 6h56m40s. Der Versuch, 5 Sekunden zum Quadrat zu nehmen, führt zu einem Überlauf (und wird nicht einmal kompiliert, wenn er mit Konstanten gemacht wird).

Übrigens entspricht die int64 Repräsentation von Dauer in Nanosekunden ungefähr "der größten darstellbaren Dauer von ungefähr 290 Jahren", was darauf hinweist, dass Dauer, wie auch int64, als vorzeichenbehafteter Wert behandelt wird: (1<<(64-1))/(1e9*60*60*24*365.25) ~= 292, und genau so ist es implementiert:

// Eine Dauer repräsentiert die verstrichene Zeit zwischen zwei Zeitpunkten
// als int64 Nanosekunden Zähler. Die Darstellung begrenzt die
// größte darstellbare Dauer auf ungefähr 290 Jahre.
type Dauer int64

Weil wir wissen, dass die zugrunde liegende Repräsentation von Dauer ein int64 ist, ist das Durchführen des Casts zwischen int64 und Dauer eine sinnvolle NO-OP - erforderlich nur um die Sprachregeln zum Mischen von Typen zu erfüllen, und es hat keinen Einfluss auf die anschließende Multiplikationsoperation.

Wenn dir das Casting aus Gründen der Reinheit nicht gefällt, vergrabe es in einem Funktionsaufruf, wie ich oben gezeigt habe.

14voto

Catsy Punkte 1160

Verwirrt von einigen Kommentaren & Diskussionen über die Multiplikation von Dauer mit Dauer, habe ich ein wenig mit den Einheiten und Funktionen herumgespielt und folgendes erhalten:

time.Second =  1s
time.Minute =  1m0s

time.Duration(1) = 1ns
time.Duration(1) * time.Millisecond =  1ms
time.Duration(1) * time.Second =  1s
time.Duration(1) * time.Minute =  1m0s

CodeJaeger.com

CodeJaeger ist eine Gemeinschaft für Programmierer, die täglich Hilfe erhalten..
Wir haben viele Inhalte, und Sie können auch Ihre eigenen Fragen stellen oder die Fragen anderer Leute lösen.

Powered by:

X