Come moltiplicare la durata per intero?


286

Per testare le goroutine simultanee, ho aggiunto una linea a una funzione per fare in modo che il ritorno torni a essere casuale (fino a un secondo)

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

Tuttavia, quando ho compilato, ho ricevuto questo errore

. \ crawler.go: 49: operazione non valida: rand.Int31n (1000) * time.Millisecond (tipi non corrispondenti int32 e time.Duration)

Qualche idea? Come posso moltiplicare una durata?

Risposte:


433

int32e time.Durationsono diversi tipi. Devi convertire int32in a time.Duration, come ad esempio time.Sleep(time.Duration(rand.Int31n(1000)) * time.Millisecond).


5
Grazie ha funzionato. Ho anche imparato a seminare il generatore di numeri casualirand.Seed(time.Now().Unix())
colonnello Panic il

44
solo per mia conoscenza, come funziona allora quanto segue? time.Sleep(time.Second * 2)
Ishan Khare,

61
Funziona perché le costanti hanno un tipo adattivo, in base al modo in cui vengono utilizzate. Vedi questo post sul blog di Rob Pike che lo spiega in dettaglio: blog.golang.org/constants
mna,

28
Questa è una di quelle cose strane in atto a causa del suo sistema di tipo semplicistico (mancanza di sovraccarico dell'operatore in questo caso) - devi lanciare la moltiplicazione su Duration* Duration= Duration, invece di quella originale che in realtà ha più senso: Duration* int= Duration.
Timmmm,

14
Bene, l'operatore che sovraccarica o la conversione numerica implicita lascerebbe che questo funzioni. Penso che abbiano ragione a lasciare fuori la conversione numerica implicita. Dopo aver ripensato a questo, int64(...) * Durationha molto più senso che lanciarlo Duration, che è solo una violazione di base del modo in cui le unità dovrebbero funzionare. Purtroppo non funziona. Devi davvero fare Duration * Durationche è orribile.
Timmmm,

61

Devi lanciarlo in un formato corretto Playground.

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

Se controllerai la documentazione per il sonno , vedrai che richiede la func Sleep(d Duration)durata come parametro. Il tuo rand.Int31n ritorna int32.

La linea dell'esempio funziona ( time.Sleep(100 * time.Millisecond)) perché il compilatore è abbastanza intelligente da capire che qui la tua costante 100 indica una durata. Ma se passi una variabile, dovresti lanciarla.


16

In Vai, puoi moltiplicare le variabili dello stesso tipo, quindi devi avere entrambe le parti dell'espressione dello stesso tipo.

La cosa più semplice che puoi fare è trasmettere un numero intero alla durata prima di moltiplicarlo, ma ciò violerebbe la semantica dell'unità. Quale sarebbe la moltiplicazione della durata per durata in termini di unità?

Preferirei convertire il tempo.Il millisecondo in un int64, quindi moltiplicarlo per il numero di millisecondi, quindi eseguire il cast nel tempo.

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

In questo modo si può dire che qualsiasi parte dell'espressione abbia un valore significativo in base al suo tipo. int64(time.Millisecond)parte è solo un valore senza dimensioni: il numero di unità di tempo più piccole nel valore originale.

Se percorri un percorso leggermente più semplice:

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

La parte sinistra della moltiplicazione è senza senso - un valore di tipo "time.Duration", che tiene qualcosa di irrilevante per il suo tipo:

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

E non è solo la semantica, c'è un'effettiva funzionalità associata ai tipi. Questo codice stampa:

100ns
100ms

È interessante notare che l'esempio di codice qui utilizza il codice più semplice, con la stessa semantica fuorviante della conversione della durata: https://golang.org/pkg/time/#Duration

secondi: = 10

fmt.Print (time.Duration (secondi) * time.Second) // stampa 10s


5

È bello che Go abbia un Durationtipo: avere unità esplicitamente definite può prevenire problemi nel mondo reale.

E a causa delle rigide regole di tipo di Go, non è possibile moltiplicare una durata per un numero intero: è necessario utilizzare un cast per moltiplicare i tipi comuni.

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

La documentazione ufficiale dimostra l'utilizzo del metodo n. 1:

Per convertire un numero intero di unità in una durata, moltiplicare:

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

Ma, naturalmente, moltiplicare una durata per una durata non dovrebbe produrre una durata - questo è insensato. Caso in questione, produce 5 millisecondi per 5 millisecondi 6h56m40s. Tentare di quadrare 5 secondi provoca un overflow (e non si compila nemmeno se fatto con costanti).

A proposito, la int64rappresentazione Durationin nanosecondi "limita la massima durata rappresentabile a circa 290 anni" , e questo indica che Duration, come int64, viene trattato come un valore con segno:, (1<<(64-1))/(1e9*60*60*24*365.25) ~= 292ed è esattamente così che viene implementato:

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

Quindi, poiché sappiamo che la rappresentazione sottostante di Durationè an int64, esegue il cast tra int64ed Durationè un sensibile NO-OP - richiesto solo per soddisfare le regole del linguaggio sui tipi di miscelazione e non ha alcun effetto sulla successiva operazione di moltiplicazione.

Se non ti piace il casting per motivi di purezza, seppelliscilo in una chiamata di funzione, come ho mostrato sopra.


"moltiplica come / con tipi comuni".
nobar,

Discussione simile relativa alla divisione alla risposta (sbagliata) qui .
Nobar

-3

Per la moltiplicazione della variabile nel tempo. Secondo usando il seguente codice

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

Questo non è un buon modo di usare le time.Durationvariabili di Go . Si assegna un nome alla variabile addOneHrDurationdi tempo time.Durationma poi si procede a impostarla su 3600 ns e non su un'ora. A time.Durationsembra avere unità base di nanosecondi. Per ottenere effettivamente una durata di un'ora potresti fare qualcosa del tipo: const oneHourDuration = 60 * time.Hour(o 3600 * time.Secondo time.Hour).
Dave C,
Utilizzando il nostro sito, riconosci di aver letto e compreso le nostre Informativa sui cookie e Informativa sulla privacy.
Licensed under cc by-sa 3.0 with attribution required.