Как умножить продолжительность на целое?

Чтобы протестировать параллельные goroutines, я добавил строку к функции, чтобы вернуть произвольное время (до одной секунды)

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

Однако когда я скомпилировал, я получил эту ошибку

.\crawler.go: 49: недопустимая операция: rand.Int31n (1000) * time.Millisecond(несогласованные типы int32 и time.Duration)

Любые идеи? Как я могу умножить продолжительность?

Ответ 1

int32 и time.Duration - разные типы. Вам нужно преобразовать int32 в time.Duration, например time.Sleep(time.Duration(rand.Int31n(1000)) * time.Millisecond).

Ответ 2

Вы должны отправить его в правильный формат Игровая площадка.

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 означает продолжительность. Но если вы передаете переменную, вы должны ее бросить.

Ответ 3

В 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

Ответ 4

Просто умножьте его так::

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.

Перейти к типу читов по умолчанию

Ответ 5

Приятно, что 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 - требуется только для удовлетворения языковых правил о смешивании типов и не влияет на последующую операцию умножения.

Если вам не нравится кастинг по соображениям чистоты, похороните его в вызове функции, как я показал выше.

Ответ 6

Для умножения переменной на время. Во-вторых, используя следующий код

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