Як помножити тривалість на ціле число?


284

Щоб перевірити паралельні функції, я додав рядок до функції, щоб змусити її повернутися випадковим часом (до однієї секунди)

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

Однак, коли я компілював, я отримав цю помилку

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

Будь-які ідеї? Як я можу помножити тривалість?

Відповіді:


431

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


5
Спасибі, що спрацювало. Я також дізнався про висівання генератора випадкових чиселrand.Seed(time.Now().Unix())
полковника Паніки

44
тільки наскільки мені відомо, як працює наступне? time.Sleep(time.Second * 2)
Ішан Харе

59
Це працює тому, що константи мають адаптивний тип, виходячи з того, як вони використовуються. Дивіться цю публікацію в блозі Роб Пайк, яка детально пояснює це: blog.golang.org/constants
1515

28
Це одна з тих дивних речей, що йдуть завдяки своїй спрощеній системі типів (відсутність перевантаження оператора в цьому випадку) - ви повинні передати множення на Duration* Duration= Duration, замість оригінальної, що насправді має більше сенсу: Duration* int= Duration.
Timmmm

14
Добре, що або перевантаження оператора, або неявне числове перетворення дозволить це працювати. Я думаю, що вони мали право виключати неявну числову конверсію. Після огляду на це, що int64(...) * Durationмає набагато більше сенсу, ніж кастинг Duration, що є лише основним порушенням того, як повинні працювати підрозділи. На жаль, це не працює. Ви дійсно повинні робити, Duration * Durationщо жахливо.
Timmmm

59

Ви повинні привести його у правильний формат 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 ви можете множити змінні одного типу, тому вам потрібно мати обидві частини виразу одного типу.

Найпростіша річ, яку ви можете зробити, - це закидання цілого числа до тривалості перед множенням, але це порушить одиничну семантику. Яке було б множення тривалості на тривалість на одиниці?

Я вважаю за краще перетворити time.Millisecond у int64, а потім помножити його на кількість мілісекунд, а потім передати на time.Duration:

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

Цікаво, що в прикладі коду тут використовується найпростіший код з однаковою оманливою семантикою перетворення тривалості: https://golang.org/pkg/time/#Duration

секунд: = 10

fmt.Print (time.Duration (секунди) * time.Second) // друкує 10с


5

Приємно, що Go має Durationтип - наявність чітко визначених одиниць може запобігти проблемам у реальному світі.

А через суворі правила правил Go, ви не можете помножити тривалість на ціле число - для множення загальних типів ви повинні використовувати команду.

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

Якщо ви не любите кастинг з чистоти, похойте його у виклику функції, як я показав вище.


"множити як / із загальними типами".
nobar

Подібна дискусія стосувалася поділу на (неправильну) відповідь тут .
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).
Дейв C
Використовуючи наш веб-сайт, ви визнаєте, що прочитали та зрозуміли наші Політику щодо файлів cookie та Політику конфіденційності.
Licensed under cc by-sa 3.0 with attribution required.