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


287

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

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

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

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

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

Ответы:


434

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


5
Спасибо, что сработало. Я также узнал о посеве генератора случайных чиселrand.Seed(time.Now().Unix())
полковник Паник

44
насколько я знаю, как тогда работает следующее? time.Sleep(time.Second * 2)
Ишан Кхаре

61
Это работает, потому что константы имеют адаптивный тип, в зависимости от того, как они используются. Посмотрите эту запись в блоге Роба Пайка, которая подробно объясняет это: blog.golang.org/constants
mna

28
Это одна из странных вещей из-за ее упрощенной системы типов (в этом случае отсутствует перегрузка операторов) - вам нужно привести умножение к Duration* Duration= Durationвместо исходного, что на самом деле имеет больше смысла: Duration* int= Duration.
Тимммм

14
Что ж, перегрузка операторов или неявное преобразование чисел позволили бы этой работе. Я думаю, что они были правы, чтобы оставить неявное преобразование чисел. Оглядываясь назад, это int64(...) * Durationимеет гораздо больше смысла, чем приведение к Duration, что является лишь основным нарушением того, как должны работать юниты. К сожалению, это не работает. Вы действительно должны сделать Duration * Durationчто ужасно.
Тимммм

62

Вы должны привести его к правильному формату Playground.

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

Если вы проверите документацию для сна , вы увидите, что она требует func Sleep(d Duration)длительности в качестве параметра. Ваш rand.Int31n возвращается int32.

Строка из примера работает ( time.Sleep(100 * time.Millisecond)), потому что компилятор достаточно умен, чтобы понять, что здесь ваша постоянная 100 означает длительность. Но если вы передадите переменную, вы должны привести ее.


16

В 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

секунд: = 10

fmt.Print (time.Duration (секунды) * time.Second) // печатает 10 с


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

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


msgstr "умножить как / с общими типами".
nobar

Подобное обсуждение связано с делением на (неправильный) ответ здесь .
Нобар

-3

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

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

Это не очень хороший способ использования time.Durationпеременных Go . Вы называете свою переменную addOneHrDurationвремени, time.Durationно затем продолжаете устанавливать ее на 3600 нс, а не на один час. А time.Durationбывает, что базовые единицы наносекунд. Чтобы фактически получить продолжительность в один час, вы можете сделать что-то вроде: const oneHourDuration = 60 * time.Hour(или 3600 * time.Secondили time.Hour).
Дейв С
Используя наш сайт, вы подтверждаете, что прочитали и поняли нашу Политику в отношении файлов cookie и Политику конфиденциальности.
Licensed under cc by-sa 3.0 with attribution required.