Как умножить duration (продолжительность) на целое число в Go?
Проблема: несоответствие типов
В Go time.Duration — это отдельный тип, основанный на int64, но не тождественный ему. Умножение разных типов запрещено строгой типизацией языка. В отличие от Python или JavaScript, Go не выполняет неявное приведение типов.
Правильное решение: явное преобразование
Нужно преобразовать множитель (int) в тип time.Duration перед умножением:
package main
import (
"fmt"
"time"
)
func main() {
baseDelay := 1 * time.Second
multiplier := 3
totalDelay := baseDelay * time.Duration(multiplier) // ✅ Правильно
fmt.Println("Total delay:", totalDelay) // Вывод: 3s
}
Почему это работает?
time.Duration(multiplier) создаёт значение типа time.Duration из целого числа. Поскольку оба операнда теперь одного типа, умножение выполняется корректно. Результат — 3 секунды.
Важные нюансы
- Единицы измерения:
time.Durationхранится в наносекундах. Умножение на 3 даёт 3×10⁹ наносекунд, что и есть 3 секунды. - Переполнение: Если множитель слишком велик, результат может переполнить int64. Для критичных случаев используйте проверки:
const maxDuration = 1<<63 - 1 // максимальное значение int64
if int64(multiplier) > maxDuration/int64(baseDelay) {
// обработка переполнения
}
Альтернативный подход: функция с проверкой
Для многократного использования можно написать вспомогательную функцию:
// MultiplyDuration безопасно умножает duration на множитель
func MultiplyDuration(d time.Duration, multiplier int) (time.Duration, error) {
if multiplier == 0 {
return 0, nil
}
if int64(multiplier) > (1<<63-1)/int64(d) {
return 0, fmt.Errorf("переполнение: %d * %d", d, multiplier)
}
return d * time.Duration(multiplier), nil
}
Работа с переменными множителями в цикле
Для вашей задачи с увеличивающейся задержкой:
func main() {
baseDelay := 1 * time.Second
for i := 1; i <= 5; i++ {
delay := baseDelay * time.Duration(i)
fmt.Printf("Пауза %d: %v\n", i, delay)
time.Sleep(delay)
}
}
Что ещё нужно знать
- Операция
time.Duration * intне разрешена, ноtime.Duration * time.Duration— тоже нет (бессмысленно). - Деление duration на int работает аналогично:
d / time.Duration(n). - Для констант (например,
3) компилятор может сам преобразовать тип, но это ненадёжно — всегда делайте явное приведение.
Теперь ваш код будет работать правильно. Главное — помнить: в Go типы должны совпадать явно.
<<Использование пакета time с константами
Если вы работаете с фиксированными множителями, можно избежать преобразования, используя константы time:
baseDelay := 1 * time.Second
totalDelay := baseDelay * 3 // ✅ Работает! 3 — это untyped-константа
Go позволяет умножать time.Duration на неименованную числовую константу (без типа). Компилятор автоматически подставляет тип time.Duration. Но как только вы присваиваете значение переменной multiplier := 3 (тип int), это перестаёт работать.
Для динамических значений
Если множитель меняется во время выполнения, используйте явное преобразование, как в первом ответе. Дополнительно можно применить time.Duration с плавающей точкой через умножение на time.Duration(factor * float64(time.Second)):
factor := 1.5
delay := time.Duration(factor * float64(time.Second))
fmt.Println(delay) // 1.5s
Этот подход удобен для дробных множителей, но будьте осторожны с потерей точности при работе с большими значениями.
Итог
- Для констант — можно без преобразования.
- Для переменных —
d * time.Duration(n). - Для дробей — через
float64.
Ответов пока нет.
Войдите чтобы оставить ответ
Блоги