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


284

为了测试并发的goroutine,我在函数中添加了一行代码,以使其花费随机的时间返回(最多一秒钟)

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

但是,当我编译时,出现此错误

。\ crawler.go:49:无效操作:rand.Int31n(1000)* time.Millisecond(int32和time.Duration类型不匹配)

有任何想法吗?如何乘以持续时间?

Answers:


430

int32time.Duration是不同的类型。您需要将转换int32time.Duration,例如time.Sleep(time.Duration(rand.Int31n(1000)) * time.Millisecond)


5
谢谢你的工作。我还了解了播种随机数发生器的知识rand.Seed(time.Now().Unix())
Panic Panic

44
就我所知,接下来的工作原理是什么? time.Sleep(time.Second * 2)
Ishan Khare 2015年

59
之所以起作用,是因为常量根据其使用方式具有自适应类型。请参阅Rob Pike 撰写的
mna 2015年

28
由于其简单的类型系统(在这种情况下没有运算符重载),这是一件很奇怪的事情-您必须将乘法强制转换为Duration* Duration= Duration,而不是原来的乘法实际上更有意义:Duration* int= Duration
Timmmm'1

14
那么,无论是运算符重载还是隐式数值转换都可以使它工作。我认为将隐式数值转换排除在外是正确的。回顾一下,这int64(...) * Duration比强制转换更有意义Duration,这只是对单元工作方式的基本违反。可悲的是这不起作用。您真的必须做Duration * Duration那可怕的事。
Timmmm '16

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)part只是一个无量纲值-原始值中最小时间单位的数量。

如果走一条稍微简单的道路:

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

顺便说一下,以纳秒int64Duration单位的表示“将可表示的最大持续时间限制为大约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

因此,因为我们知道的基本表示形式Durationint64,执行之间的转换,int64并且Duration是明智的NO-OP -仅需满足有关混合类型的语言规则,并且对后续的乘法运算没有影响。

如果您出于纯粹的原因不喜欢转换,则将其埋入函数调用中,如上所示。


普通类型相乘”。
nobar

此处有关(错误)答案的划分相关的类似讨论。
nobar

-3

用于将变量乘以时间。其次使用以下代码

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

这不是使用Go time.Duration变量的好方法。您addOneHrDuration为时间变量命名,time.Duration但随后将其设置为3600 ns,而不是一小时。一个time.Duration恰好具有纳秒的基本单位。要获得一个小时的持续时间,您可以执行以下操作const oneHourDuration = 60 * time.Hour:(或3600 * time.Secondtime.Hour)。
戴夫C,
By using our site, you acknowledge that you have read and understand our Cookie Policy and Privacy Policy.
Licensed under cc by-sa 3.0 with attribution required.