Wie multipliziere ich die Dauer mit einer ganzen Zahl?


284

Um gleichzeitige Goroutinen zu testen, habe ich einer Funktion eine Zeile hinzugefügt, damit die Rückkehr eine zufällige Zeit in Anspruch nimmt (bis zu einer Sekunde).

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

Beim Kompilieren wurde jedoch dieser Fehler angezeigt

. \ 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?

Antworten:


430

int32und time.Durationsind verschiedene Arten. Sie müssen das int32in ein konvertieren time.Duration, wie z time.Sleep(time.Duration(rand.Int31n(1000)) * time.Millisecond).


5
Danke, das hat funktioniert. Ich habe auch gelernt, wie man den Zufallszahlengenerator aussätrand.Seed(time.Now().Unix())
Colonel Panic

44
Wie funktioniert dann nach meinem Wissen das Folgende? time.Sleep(time.Second * 2)
Ishan Khare

59
Dies funktioniert, weil Konstanten einen adaptiven Typ haben, der davon abhängt, wie sie verwendet werden. Siehe diesen Blog-Beitrag von Rob Pike, der es im Detail erklärt: blog.golang.org/constants
mna

28
Dies ist eines dieser seltsamen Dinge aufgrund seines vereinfachten Typsystems (in diesem Fall mangelnde Überladung des Operators) - Sie müssen die Multiplikation auf Duration* Duration= setzen Duration, anstatt auf die ursprüngliche, die tatsächlich sinnvoller ist: Duration* int= Duration.
Timmmm

14
Nun, entweder eine Überladung des Operators oder eine implizite numerische Konvertierung würde dies funktionieren lassen. Ich denke, sie hatten Recht, die implizite numerische Konvertierung wegzulassen. Wenn man zurückblickt, int64(...) * Durationist das viel sinnvoller als das Casting Duration, was nur eine grundlegende Verletzung der Funktionsweise von Einheiten darstellt. Leider funktioniert das nicht. Sie müssen wirklich tun, Duration * Durationwas schrecklich ist.
Timmmm

59

Sie müssen es in ein korrektes Format umwandeln Playground.

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

Wenn Sie die Dokumentation auf Schlaf prüfen , sehen Sie, dass die func Sleep(d Duration)Dauer als Parameter erforderlich ist. Ihr rand.Int31n kehrt zurück int32.

Die Zeile aus dem Beispiel funktioniert ( time.Sleep(100 * time.Millisecond)), weil der Compiler klug genug ist, um zu verstehen, dass hier Ihre Konstante 100 eine Dauer bedeutet. Wenn Sie jedoch eine Variable übergeben, sollten Sie sie umwandeln.


16

In Go können Sie Variablen desselben Typs multiplizieren, sodass beide Teile des Ausdrucks denselben Typ haben müssen.

Das Einfachste, was Sie tun können, ist, vor dem Multiplizieren eine Ganzzahl in die Dauer umzuwandeln. Dies würde jedoch die Einheitensemantik verletzen. Was wäre eine Multiplikation von Dauer mit Dauer in Einheiten?

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

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

Auf diese Weise kann gesagt werden, dass jeder Teil des Ausdrucks je nach Typ einen aussagekräftigen Wert hat. int64(time.Millisecond)Teil ist nur ein dimensionsloser Wert - die Anzahl der kleinsten Zeiteinheiten im ursprünglichen Wert.

Wenn Sie einen etwas einfacheren Weg gehen:

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

Der linke Teil der Multiplikation ist Unsinn - ein Wert vom Typ "time.Duration", der etwas enthält, das für seinen Typ irrelevant ist:

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

Und es ist nicht nur Semantik, es gibt tatsächliche Funktionen, die mit Typen verbunden sind. Dieser Code druckt:

100ns
100ms

Interessanterweise verwendet das Codebeispiel hier den einfachsten Code mit derselben irreführenden Semantik der Dauerkonvertierung: https://golang.org/pkg/time/#Duration

Sekunden: = 10

fmt.Print (time.Duration (Sekunden) * time.Second) // druckt 10s


5

Es ist schön, dass Go einen DurationTyp hat - explizit definierte Einheiten können reale Probleme verhindern.

Und aufgrund der strengen Typregeln von Go können Sie eine Dauer nicht mit einer Ganzzahl multiplizieren. Sie müssen eine Umwandlung verwenden, um allgemeine Typen zu multiplizieren.

/*
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'
}

Die offizielle Dokumentation zeigt die Verwendung von Methode 1:

Um eine ganzzahlige Anzahl von Einheiten in eine Dauer umzuwandeln, multiplizieren Sie:

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

Aber das Multiplizieren einer Dauer mit einer Dauer sollte natürlich keine Dauer ergeben - das ist auf den ersten Blick unsinnig. In diesem Fall werden 5 Millisekunden mal 5 Millisekunden erzeugt 6h56m40s. Der Versuch, 5 Sekunden zu quadrieren, führt zu einem Überlauf (und wird nicht einmal kompiliert, wenn Konstanten verwendet werden).

Übrigens begrenzt die int64Darstellung Durationin Nanosekunden "die größte darstellbare Dauer auf ungefähr 290 Jahre" , und dies zeigt an, dass Durationwie int64ein vorzeichenbehafteter Wert behandelt wird: (1<<(64-1))/(1e9*60*60*24*365.25) ~= 292und genau so wird es implementiert:

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

Also, weil wir wissen, dass die zugrunde liegende Darstellung von Durationein int64ist, das Casting zwischen int64und Durationein vernünftiges NO-OP ist - nur erforderlich, um Sprachregeln über das Mischen von Typen zu erfüllen, und es hat keine Auswirkung auf die nachfolgende Multiplikationsoperation.

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


"Multiplizieren als / mit gängigen Typen".
Nobar

Eine ähnliche Diskussion bezog sich auf die Teilung bei der (falschen) Antwort hier .
Nobar

-3

Zur Multiplikation der Variablen mit der Zeit. Zweitens mit folgendem Code

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

Dies ist keine gute Möglichkeit, die time.DurationVariablen von Go zu verwenden . Sie nennen Ihre Variable addOneHrDurationZeit , time.Durationaber dann gehen sie nicht zu einer Stunde auf 3600 ns einzustellen. A hat time.Durationzufällig Basiseinheiten von Nanosekunden. Um tatsächlich eine Stunde zu erhalten, können Sie Folgendes tun: const oneHourDuration = 60 * time.Hour(oder 3600 * time.Secondoder time.Hour).
Dave C
Durch die Nutzung unserer Website bestätigen Sie, dass Sie unsere Cookie-Richtlinie und Datenschutzrichtlinie gelesen und verstanden haben.
Licensed under cc by-sa 3.0 with attribution required.