如何将持续时间乘以整数?

为了测试并发的gorout例程,我在函数中添加了一行,使其返回的时间随机(最多一秒)

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

然而,当我编译时,我得到了这个错误

\履带。go:49:无效操作:rand.Int31n(1000) *时间。毫秒(类型int32和time.Duration不匹配)

什么好主意吗?如何乘以持续时间?

276154 次浏览

int32time.Duration是不同的类型。你需要将int32转换为time.Duration:

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

你必须将它转换为正确的格式游乐场 .

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

如果你检查睡眠的文档,你会看到它需要func Sleep(d Duration) duration作为参数。你的兰德。Int31n返回int32

示例中的这行代码可以工作(time.Sleep(100 * time.Millisecond)),因为编译器足够聪明,可以理解这里的常数 100表示持续时间。但如果你传递一个变量,你应该强制转换它。

就像这样乘:

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,可以被数值型无类型整数使用。


👉我在这个帖子中写了这些细节。

Go Default Types Cheatsheet

在Go中,你可以将相同类型的变量相乘,所以你需要让表达式的两个部分具有相同的类型。

您可以做的最简单的事情是在相乘之前将一个整数转换为duration,但这将违反单元语义。持续时间乘以持续时间的单位是多少?

我宁愿转换时间。毫秒转换为int64,然后将其乘以毫秒数,然后转换为time。持续时间:

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(seconds)*time.Second) //打印10秒

变量乘以时间。第二次使用以下代码

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

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秒会导致溢出(如果使用常量,甚至不会编译)。

另外,Durationint64表示形式(以纳秒为单位)"将最大可表示持续时间限制为大约290年",这表明Durationint64一样,被视为有符号值:(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,所以在int64Duration之间执行强制转换是一个合理的no - op——只需要满足关于混合类型的语言规则,并且它对后续的乘法操作没有影响。

如果出于纯粹的原因不喜欢这种类型转换,就像我上面所示的那样,将它隐藏在一个函数调用中。

轮到我:

https://play.golang.org/p/RifHKsX7Puh

package main


import (
"fmt"
"time"
)


func main() {
var n int = 77
v := time.Duration( 1.15 * float64(n) ) * time.Second


fmt.Printf("%v %T", v, v)
}

记住一个简单的事实是有帮助的,那就是时间。Duration仅为int64,其中包含纳秒值。

这样,时间转换。持续时间成了一种形式。只需记住:

  • int64
  • 总是nanosecs

你可以使用时间。ParseDuration

ms := rand.Int31n(1000)
duration, err := time.ParseDuration(fmt.Sprintf(
"%vms",
ms,
))

困惑的一些评论&关于DurationDuration相乘的讨论,我对单位和函数进行了一些处理,得到了这样的结果:

time.Second =  1s
time.Minute =  1m0s


time.Duration(1) = 1ns
time.Duration(1) * time.Millisecond =  1ms
time.Duration(1) * time.Second =  1s
time.Duration(1) * time.Minute =  1m0s