首页 > 解决方案 > Go 允许算术运算溢出而不是抛出异常是预期的行为吗?

问题描述

我正在将一些 Go 代码移植到 Rust,并且我意识到当乘法期间发生溢出时 Rust 会发生恐慌,而 Go 允许发生溢出。

下面的测试代码,不会导致溢出但打印减少的值。(通过:https ://play.golang.org/ 测试)

func main() {
    fmt.Println("test\n")
    var key uint64 = 15000;

    key = key*2862933555777941757 + 1

    fmt.Println(key)
}

标签: gointeger-overflow

解决方案


规格:整数溢出:

对于无符号整数值,运算 +、-、* 和 << 以 2 n为模计算,其中n是无符号整数类型的位宽。粗略地说,这些无符号整数运算在溢出时会丢弃高位,并且程序可能依赖于“环绕”

对于有符号整数,操作 +、-、*、/ 和 << 可能合法溢出,并且结果值存在并且由有符号整数表示、操作及其操作数确定性地定义。溢出不会导致运行时恐慌在不发生溢出的假设下,编译器可能不会优化代码。例如,它可能并不认为这x < x + 1总是正确的。

如上所述,溢出存在并且它不会导致运行时恐慌。

但是必须小心,就好像你有一个常量表达式一样,因为它们具有任意精度,如果要将结果转换为不适合目标类型有效范围的固定精度,则会导致编译时间 -错误。

例如:

const maxuint64 = 0xffffffffffffffff
var key uint64 = maxuint64 * maxuint64

fmt.Println(key)

以上产生:

constant 340282366920938463426481119284349108225 overflows uint64

maxuint64 * maxuint64是一个经过正确计算的常量表达式(其值为340282366920938463426481119284349108225),但是当将此值分配给keytype 的变量时uint64,会导致编译时错误,因为该值不能由 type 的值表示uint64。但这不是运行时恐慌。

查看相关问题:

Golang:故意int溢出

Go 编译器对常量表达式和其他表达式的评估是否不同

如何在不溢出的情况下将大 float64 存储在字符串中?

在 Go 中将 uint16 转换为 int16 的正确方法


推荐阅读