我有一个包含负数的int64变量,我希望从包含正数的uint64变量中减去它:
var endTime uint64
now := time.Now().Unix()
endTime = uint64(now)
var interval int64
interval = -3600
endTime = endTime + uint64(interval)上面的代码似乎可以工作,但我想知道我是否可以依赖它。作为一个新手,我很惊讶,在将负数转换为uint64之后,它仍然是负数--我原本计划减去现在的正值(在转换之后),以获得我想要的结果。
发布于 2018-06-12 19:23:28
将有符号数转换为无符号数将不会保留为负数,因为无符号类型的有效范围不包括负数。如果打印uint(interval),您肯定会看到打印的正数。
你所经历的是确定性的,你可以依赖它(但这并不意味着你应该)。它是Go (和大多数其他编程语言)使用2's completement表示存储有符号整数类型的结果。
这意味着在负数的情况下,使用n位,值-x (其中x为正)被存储为正值2^n - x的二进制表示。这样做的好处是,数字可以按位相加,并且无论它们是负数还是正数,结果都是正确的。
所以当你有一个带符号的负数时,它基本上存储在内存中,就像你从0中减去它的绝对值一样。这意味着如果您将负的有符号的值转换为无符号的值,并将其添加到无符号的值中,结果将是正确的,因为将以一种有用的方式发生溢出。
将int64类型的值转换为uint64不会更改内存布局,只会更改类型。那么int64有什么8个字节,转换后的uint64也会有同样的8个字节。如上所述,存储在那8个字节中的表示是与值0 - abs(x)的位模式相同的位模式。因此,转换的结果将是一个数字,如果您在无符号世界中从0中减去abs(x),就会得到一个数字。是的,这不会是负数(因为类型是无符号的),相反,它将是一个“大”数字,从uint64类型的最大值开始倒数。但是如果你把一个比abs(x)大的y数加到这个“大”数上,就会发生溢出,结果就像y - abs(x)。
请看这个演示发生了什么的简单示例(在Go Playground上试试):
a := uint8(100)
b := int8(-10)
fmt.Println(uint8(b)) // Prints 226 which is: 0 - 10 = 256 - 10
a = a + uint8(b)
fmt.Println(a) // Prints 90 which is: 100 + 226 = 326 = 90
// after overflow: 326 - 256 = 90如上所述,您不应该依赖这一点,因为这可能会导致混淆。如果您打算使用负数,则使用有符号类型。
如果您使用的代码库已经使用了uint64值,则使用uint64值进行减法而不是加法:
interval := uint64(3600)
endTime -= interval另请注意,如果您有time.Time值,则应该利用它的Time.Add()方法:
func (t Time) Add(d Duration) Time您可以指定要添加到时间中的time.Duration,如果您想要返回时间,则该值可能为负值,如下所示:
t := time.Now()
t = t.Add(-3600 * time.Second)time.Duration更具表现力:我们看到上面指定的值显式地使用秒。
https://stackoverflow.com/questions/50815512
复制相似问题