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

huangapple go评论86阅读模式
英文:

How to multiply duration by integer?

问题

为了测试并发的goroutines,我在一个函数中添加了一行代码,使其在返回之前需要随机的时间(最多一秒)。

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

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

> .\crawler.go:49: invalid operation: rand.Int31n(1000) * time.Millisecond (mismatched types int32 and time.Duration)

有什么想法吗?我如何将一个持续时间乘以一个数值?

英文:

To test concurrent goroutines, I added a line to a function to make it take a random time to return (up to one second)

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

However when I compiled, I got this error

> .\crawler.go:49: invalid operation: rand.Int31n(1000) * time.Millisecond (mismatched types int32 and time.Duration)

Any ideas? How can I multiply a duration?

答案1

得分: 722

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

time.Sleep(time.Duration(rand.Int31n(1000)) * time.Millisecond)
英文:

int32 and time.Duration are different types. You need to convert the int32 to a time.Duration:

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

答案2

得分: 84

你必须将其转换为正确的格式<kbd>Playground</kbd>。

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

如果你查看sleep的文档,你会发现它需要func Sleep(d Duration)作为参数的持续时间。你的rand.Int31n返回int32

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

英文:

You have to cast it to a correct format <kbd>Playground</kbd>.

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

If you will check documentation for sleep, you see that it requires func Sleep(d Duration) duration as a parameter. Your rand.Int31n returns int32.

The line from the example works (time.Sleep(100 * time.Millisecond)) because the compiler is smart enough to understand that here your constant 100 means a duration. But if you pass a variable, you should cast it.

答案3

得分: 26

在Go语言中,你可以对相同类型的变量进行乘法运算,所以你需要确保表达式的两个部分具有相同的类型。

最简单的方法是在进行乘法运算之前将整数转换为时间间隔(duration),但这将违反单位语义。关于时间间隔乘以时间间隔的单位是什么?

我更倾向于将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
// 对于下面的部分,我只是无法想出一个名字:
someLHS := time.Duration(numberOfMilliseconds)
fmt.Println(someLHS)
fmt.Println(someLHS*time.Millisecond)

这不仅仅是语义问题,类型还与实际功能相关。
这段代码输出:

100ns
100ms

有趣的是,这里的代码示例使用了最简单的代码,具有相同具有误导性的Duration转换语义:https://golang.org/pkg/time/#Duration

> seconds := 10
>
> fmt.Print(time.Duration(seconds)*time.Second) // 输出 10s

英文:

In Go, you can multiply variables of same type, so you need to have both parts of the expression the same type.

The simplest thing you can do is casting an integer to duration before multiplying, but that would violate unit semantics. What would be multiplication of duration by duration in term of units?

I'd rather convert time.Millisecond to an int64, and then multiply it by the number of milliseconds, then cast to time.Duration:

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

This way any part of the expression can be said to have a meaningful value according to its type. int64(time.Millisecond) part is just a dimensionless value - the number of smallest units of time in the original value.

If walk a slightly simpler path:

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

The left part of multiplication is nonsense - a value of type "time.Duration", holding something irrelevant to its type:

numberOfMilliseconds := 100
// just can&#39;t come up with a name for following:
someLHS := time.Duration(numberOfMilliseconds)
fmt.Println(someLHS)
fmt.Println(someLHS*time.Millisecond)

And it's not just semantics, there is actual functionality associated with types.
This code prints:

100ns
100ms

Interestingly, the code sample here uses the simplest code, with the same misleading semantics of Duration conversion: https://golang.org/pkg/time/#Duration

> seconds := 10
>
> fmt.Print(time.Duration(seconds)*time.Second) // prints 10s

答案4

得分: 14

很好,Go语言有一个Duration类型 -- 明确定义单位可以防止现实世界中的问题。

由于Go语言的严格类型规则,你不能将一个Duration乘以一个整数 -- 你必须使用类型转换才能乘以常见类型。

/*
MultiplyDuration 将语义上无效的持续时间乘法隐藏在函数后面
*/
func MultiplyDuration(factor int64, d time.Duration) time.Duration {
    return time.Duration(factor) * d        // 方法1 -- 在`Duration`中进行乘法
 // return time.Duration(factor * int64(d)) // 方法2 -- 在`int64`中进行乘法
}

官方文档演示了使用方法1:

> 要将单位的整数数量转换为Duration,进行乘法运算:

seconds := 10
fmt.Print(time.Duration(seconds)*time.Second) // 输出10s

但是,当然,将一个持续时间乘以一个持续时间不应该产生一个持续时间 -- 这在表面上是荒谬的。例如,5毫秒乘以5毫秒会产生6h56m40s。尝试对5秒进行平方会导致溢出(如果使用常量进行操作,甚至无法编译)。

顺便说一下,Duration在纳秒中的int64表示法“将最大可表示的持续时间限制在大约290年”,这表明Durationint64一样被视为有符号值:(1&lt;&lt;(64-1))/(1e9*60*60*24*365.25) ~= 292,这正是它的实现方式:

// Duration表示两个时刻之间经过的时间
// 以int64纳秒计数表示。该表示法将最大可表示的持续时间限制在大约290年。
type Duration int64

因此,因为我们知道Duration的底层表示是int64,在int64Duration之间进行类型转换是一个明智的无操作 -- 只是为了满足语言对混合类型的规则要求,并且对后续的乘法操作没有影响。

如果你不喜欢类型转换,出于纯粹性的原因,可以像我上面展示的那样将其隐藏在一个函数调用中。

英文:

It's nice that Go has a Duration type -- having explicitly defined units can prevent real-world problems.

And because of Go's strict type rules, you can't multiply a Duration by an integer -- you must use a cast in order to multiply common types.

/*
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 &#39;Duration&#39;
 // return time.Duration(factor * int64(d)) // method 2 -- multiply in &#39;int64&#39;
}

The official documentation demonstrates using method #1:

> To convert an integer number of units to a Duration, multiply:

seconds := 10
fmt.Print(time.Duration(seconds)*time.Second) // prints 10s

But, of course, multiplying a duration by a duration should not produce a duration -- that's nonsensical on the face of it. Case in point, 5 milliseconds times 5 milliseconds produces 6h56m40s. Attempting to square 5 seconds results in an overflow (and won't even compile if done with constants).

By the way, the int64 representation of Duration in nanoseconds "limits the largest representable duration to approximately 290 years", and this indicates that Duration, like int64, is treated as a signed value: (1&lt;&lt;(64-1))/(1e9*60*60*24*365.25) ~= 292, and that's exactly how it is implemented:

// 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

So, because we know that the underlying representation of Duration is an int64, performing the cast between int64 and Duration is a sensible NO-OP -- required only to satisfy language rules about mixing types, and it has no effect on the subsequent multiplication operation.

If you don't like the the casting for reasons of purity, bury it in a function call as I have shown above.

答案5

得分: 10

对于一些关于将DurationDuration相乘的评论和讨论感到困惑,我进行了一些单位和函数的尝试,得到了以下结果:

time.Second =  1秒
time.Minute =  1分钟

time.Duration(1) = 1纳秒
time.Duration(1) * time.Millisecond =  1毫秒
time.Duration(1) * time.Second =  1秒
time.Duration(1) * time.Minute =  1分钟```

<details>
<summary>英文:</summary>

Confused by some of the comments &amp; discussions on multiplying `Duration` with `Duration`, I played around a bit with the units and functions and got this:

```time.Millisecond =  1ms
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

</details>



# 答案6
**得分**: 2

只返回翻译好的部分:

**Just multiply it like this**: 

    time.Sleep(1000 * time.Millisecond)

You don't need to convert it.

---

**Reasoning:**

`1000`是一个无类型的字面常量,其默认类型为整数,它有一个理想类型。

`1000 * time.Millisecond`可以直接使用,因为Go会自动将无类型常量转换为数值类型。在这里,它会自动将`1000`转换为`time.Duration`,因为它是[Int64](https://golang.org/src/time/time.go?s=21095:21114#L610)的别名。

**Millisecond的定义如下:**

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

----

&#128073; 我在这篇[文章](https://blog.learngoprogramming.com/learn-golang-typed-untyped-constants-70b4df443b61)中详细介绍了这些细节。

[![Go默认类型速查表][1]][1]


  [1]: https://i.stack.imgur.com/nzGsU.png

<details>
<summary>英文:</summary>

**Just multiply it like this**: 

    time.Sleep(1000 * time.Millisecond)

You don&#39;t need to convert it.

---

**Reasoning:**

`1000` is an untyped literal constant with a default type of integer, it has an _ideal type_.

`1000 * time.Millisecond` can be used directly because, Go converts the untyped constants to numeric types automatically. Here, it converts `1000` to `time.Duration` automatically, because it&#39;s an alias to [Int64](https://golang.org/src/time/time.go?s=21095:21114#L610).

**Millisecond defined like this:**

    type Duration int64
    
    const (
        Nanosecond  Duration = 1
        Microsecond          = 1000 * Nanosecond
        Millisecond          = 1000 * Microsecond
        Second               = 1000 * Millisecond
        Minute               = 60 * Second
        Hour                 = 60 * Minute
    )

`Millisecond` has `time.Duration` type, but, underlying, it&#39;s an `int64` which is assignable and can be used by a _numeric untyped integer_.

----

&#128073; I wrote about these details here in this [post](https://blog.learngoprogramming.com/learn-golang-typed-untyped-constants-70b4df443b61).

[![Go Default Types Cheatsheet][1]][1]


  [1]: https://i.stack.imgur.com/nzGsU.png

</details>



# 答案7
**得分**: 0

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)
    }

记住一个简单的事实很有帮助,即底层上,time.Duration只是一个保存纳秒值的int64。

这样,转换到/从time.Duration就变得很简单。只需记住:
- int64
- 总是纳秒

<details>
<summary>英文:</summary>

My turn:

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

    package main
    
    import (
    	&quot;fmt&quot;
    	&quot;time&quot;
    )
    
    func main() {
    	var n int = 77
    	v := time.Duration( 1.15 * float64(n) ) * time.Second
    
    	fmt.Printf(&quot;%v %T&quot;, v, v)
    }

It helps to remember the simple fact, that underlyingly the time.Duration is a mere int64, which holds nanoseconds value.

This way, conversion to/from time.Duration becomes a formality. Just remember:
- int64
- always nanosecs

</details>



# 答案8
**得分**: 0

你可以使用[time.ParseDuration](https://pkg.go.dev/time#ParseDuration)。

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

You can use time.ParseDuration.

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

答案9

得分: -4

对于使用以下代码将变量乘以time.Second进行乘法运算

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

For multiplication of variable to time.Second using following code

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

huangapple
  • 本文由 发表于 2013年7月10日 22:23:44
  • 转载请务必保留本文链接:https://go.coder-hub.com/17573190.html
匿名

发表评论

匿名网友

:?: :razz: :sad: :evil: :!: :smile: :oops: :grin: :eek: :shock: :???: :cool: :lol: :mad: :twisted: :roll: :wink: :idea: :arrow: :neutral: :cry: :mrgreen:

确定