Ответ 1
int32
и time.Duration
- разные типы. Вам нужно преобразовать int32
в time.Duration
, например time.Sleep(time.Duration(rand.Int31n(1000)) * time.Millisecond)
.
Чтобы протестировать параллельные goroutines, я добавил строку к функции, чтобы вернуть произвольное время (до одной секунды)
time.Sleep(rand.Int31n(1000) * time.Millisecond)
Однако когда я скомпилировал, я получил эту ошибку
.\crawler.go: 49: недопустимая операция: rand.Int31n (1000) * time.Millisecond(несогласованные типы int32 и time.Duration)
Любые идеи? Как я могу умножить продолжительность?
int32
и time.Duration
- разные типы. Вам нужно преобразовать int32
в time.Duration
, например time.Sleep(time.Duration(rand.Int31n(1000)) * time.Millisecond)
.
Вы должны отправить его в правильный формат Игровая площадка.
yourTime := rand.Int31n(1000)
time.Sleep(time.Duration(yourTime) * time.Millisecond)
Если вы проверите документацию для sleep, вы увидите, что для параметра требуется func Sleep(d Duration)
duration. Ваш rand.Int31n возвращает int32
.
Строка из примера работает (time.Sleep(100 * time.Millisecond)
), потому что компилятор достаточно умен, чтобы понять, что здесь constant 100 означает продолжительность. Но если вы передаете переменную, вы должны ее бросить.
В Go вы можете умножать переменные одного типа, поэтому вам нужно, чтобы обе части выражения были одного типа.
Самая простая вещь, которую вы можете сделать, это привести целое число к длительности перед умножением, но это нарушит семантику юнитов. Каково будет умножение длительности на длительность в единицах измерения?
Я предпочел бы преобразовать время. Миллисекунды в int64, а затем умножить его на количество миллисекунд, а затем привести к времени. Продолжительность:
time.Duration(int64(time.Millisecond) * int64(rand.Int31n(1000)))
Таким образом, можно сказать, что любая часть выражения имеет значимое значение в соответствии с его типом. Часть int64(time.Millisecond)
- это просто безразмерное значение - количество наименьших единиц времени в исходном значении.
Если идти по несколько более простому пути:
time.Duration(rand.Int31n(1000)) * time.Millisecond
Левая часть умножения - нонсенс - значение типа "time.Duration", содержащее нечто, не относящееся к его типу:
numberOfMilliseconds := 100
// just can't come up with a name for following:
someLHS := time.Duration(numberOfMilliseconds)
fmt.Println(someLHS)
fmt.Println(someLHS*time.Millisecond)
И это не просто семантика, это фактическая функциональность, связанная с типами. Этот код печатает:
100ns
100ms
Интересно, что в данном примере кода используется простейший код с той же вводящей в заблуждение семантикой преобразования Duration: https://golang.org/pkg/time/#Duration
seconds := 10
fmt.Print(time.Duration(seconds)*time.Second)//prints 10s
Просто умножьте его так::
time.Sleep(1000 * time.Millisecond)
Вам не нужно его преобразовывать.
Рассуждение:
1000
- это нетипизированная константа литерала с целым числом по умолчанию, оно имеет идеальный тип.
1000 * time.Millisecond
может использоваться напрямую, потому что Go автоматически преобразует нетипизированные константы в числовые типы. Здесь он автоматически преобразует 1000
в time.Duration
, потому что это псевдоним Int64.
Миллисекунда определяется следующим образом:
type Duration int64
const (
Nanosecond Duration = 1
Microsecond = 1000 * Nanosecond
Millisecond = 1000 * Microsecond
Second = 1000 * Millisecond
Minute = 60 * Second
Hour = 60 * Minute
)
Millisecond
имеет тип time.Duration
, но, лежащий в основе, он int64
, который можно присваивать и может использоваться числовым нетипизированным целым числом.
👉 Я писал об этих деталях здесь, в post.
Приятно, что Go имеет тип Duration
- наличие явно определенных единиц может предотвратить реальные проблемы.
А из-за строгих правил типа Go вы не можете умножить Duration на целое число - вы должны использовать приведение для умножения общих типов.
/*
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'
}
Официальная документация демонстрирует использование метода № 1:
Чтобы преобразовать целое число единиц в длительность, умножьте:
seconds := 10
fmt.Print(time.Duration(seconds)*time.Second) // prints 10s
Но, конечно, умножение длительности на длительность не должно приводить к длительности - что бессмысленно на первый взгляд. Например, 5 миллисекунд умножают на 5 миллисекунд 6h56m40s
. Попытка возвести в квадрат 5 секунд приводит к переполнению (и даже не скомпилируется, если сделано с константами).
Кстати, int64
представление Duration
в наносекундах "ограничивает наибольшую представляемую продолжительность примерно 290 годами", и это указывает на то, что Duration
, как и int64
, рассматривается как значение со знаком: (1<<(64-1))/(1e9*60*60*24*365.25) ~= 292
, и как именно это реализовано:
// 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
Итак, поскольку мы знаем, что базовое представление Duration
является int64
, выполнение приведения между int64
и Duration
является разумным NO-OP - требуется только для удовлетворения языковых правил о смешивании типов и не влияет на последующую операцию умножения.
Если вам не нравится кастинг по соображениям чистоты, похороните его в вызове функции, как я показал выше.
Для умножения переменной на время. Во-вторых, используя следующий код
oneHr:=3600
addOneHrDuration :=time.Duration(oneHr)
addOneHrCurrTime := time.Now().Add(addOneHrDuration*time.Second)