Como multiplicar a duração pelo número inteiro?

284

Para testar goroutines simultâneos, adicionei uma linha a uma função para fazer com que demorasse um tempo aleatório para retornar (até um segundo)

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

No entanto, quando compilei, recebi este erro

. \ crawler.go: 49: operação inválida: rand.Int31n (1000) * time.Millisecond (tipos incompatíveis int32 e time.Duration)

Alguma ideia? Como posso multiplicar uma duração?

Coronel Panic
fonte

Respostas:

430

int32e time.Durationsão tipos diferentes. Você precisa converter o int32para a time.Duration, como time.Sleep(time.Duration(rand.Int31n(1000)) * time.Millisecond).

mna
fonte
5
Graças que funcionou. Eu também aprendi sobre semear o gerador de números aleatóriosrand.Seed(time.Now().Unix())
Coronel Pânico
44
Pelo que sei, como funciona o seguinte? time.Sleep(time.Second * 2)
Ishan Khare
59
Funciona porque as constantes têm um tipo adaptável, com base em como são usadas. Veja este post de Rob Pike que explica em detalhes: blog.golang.org/constants
mna
28
Essa é uma daquelas coisas estranhas devido ao seu sistema de tipos simplista (falta de sobrecarga do operador neste caso) - você deve converter a multiplicação em Duration* Duration= Duration, em vez da original que realmente faz mais sentido: Duration* int= Duration.
precisa saber é o seguinte
14
Bem, a sobrecarga do operador ou a conversão numérica implícita deixariam isso funcionar. Eu acho que eles estavam certos em deixar de fora a conversão numérica implícita. Depois de olhar para trás, isso int64(...) * Durationfaz muito mais sentido do que lançar para Duration, o que é apenas uma violação básica de como as unidades devem funcionar. Infelizmente isso não funciona. Você realmente tem que fazer o Duration * Durationque é horrível.
Timmmm
59

Você precisa convertê-lo para o formato correto Playground.

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

Se você verificar a documentação para suspensão , verá que ela requer func Sleep(d Duration)duração como parâmetro. Seu rand.Int31n retorna int32.

A linha do exemplo funciona ( time.Sleep(100 * time.Millisecond)) porque o compilador é inteligente o suficiente para entender que aqui sua constante 100 significa uma duração. Mas se você passa uma variável, deve convertê-la.

Salvador Dalí
fonte
16

No Go, você pode multiplicar variáveis ​​do mesmo tipo, portanto, você precisa ter as duas partes da expressão do mesmo tipo.

A coisa mais simples que você pode fazer é converter um número inteiro para a duração antes da multiplicação, mas isso violaria a semântica da unidade. O que seria multiplicação de duração por duração em termos de unidades?

Eu prefiro converter o tempo. Milissegundo em um int64 e, em seguida, multiplique-o pelo número de milissegundos e, em seguida, faça a conversão para o tempo.

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

Dessa forma, pode-se dizer que qualquer parte da expressão possui um valor significativo de acordo com seu tipo. int64(time.Millisecond)parte é apenas um valor sem dimensão - o número de menores unidades de tempo no valor original.

Se seguir um caminho um pouco mais simples:

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

A parte esquerda da multiplicação é um absurdo - um valor do tipo "time.Duration", mantendo algo irrelevante para o seu 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 não é apenas semântica, há uma funcionalidade real associada aos tipos. Este código imprime:

100ns
100ms

Curiosamente, o exemplo de código aqui usa o código mais simples, com a mesma semântica enganosa da conversão de Duração: https://golang.org/pkg/time/#Duration

segundos: = 10

fmt.Print (time.Duration (segundos) * time.Second) // imprime 10s

George Polevoy
fonte
5

É bom que o Go tenha um Durationtipo - ter unidades explicitamente definidas pode evitar problemas do mundo real.

E, devido às regras estritas de Go, você não pode multiplicar uma Duração por um número inteiro - você deve usar uma conversão para multiplicar tipos comuns.

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

A documentação oficial demonstra o uso do método 1:

Para converter um número inteiro de unidades em uma duração, multiplique:

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

Mas, é claro, multiplicar uma duração por uma duração não deve produzir uma duração - isso não faz sentido. Caso em questão, 5 milissegundos vezes 5 milissegundos produz 6h56m40s. Tentar quadrado 5 segundos resulta em um estouro (e nem será compilado se for feito com constantes).

A propósito, a int64representação Durationem nanossegundos "limita a maior duração representável a aproximadamente 290 anos" , e isso indica que Duration, assim int64, é tratado como um valor assinado: (1<<(64-1))/(1e9*60*60*24*365.25) ~= 292e é exatamente assim que é implementado:

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

Portanto, porque sabemos que a representação subjacente de Durationé um int64, executando o elenco entre int64e Durationé um NO-OP sensível - necessário apenas para satisfazer as regras de linguagem sobre tipos de mistura, e não tem efeito na operação de multiplicação subsequente.

Se você não gostar do elenco por razões de pureza, enterre-o em uma chamada de função, como mostrei acima.

nobar
fonte
"multiplique como / com tipos comuns".
Nobar
Discussão semelhante relacionada à divisão na resposta (errada) aqui .
nobar 25/02
-3

Para multiplicação da variável em time.Second usando o seguinte código

    oneHr:=3600
    addOneHrDuration :=time.Duration(oneHr)
    addOneHrCurrTime := time.Now().Add(addOneHrDuration*time.Second)
delroy.santos
fonte
Esta não é uma boa maneira de usar as time.Durationvariáveis do Go . Você nomeia sua variável addOneHrDurationde tempo, time.Durationmas depois define-a para 3600 ns e não para uma hora. A time.Durationpossui unidades básicas de nanossegundos. Para obter uma duração de uma hora, você pode fazer algo como: const oneHourDuration = 60 * time.Hour(ou 3600 * time.Secondou time.Hour).
Dave C