Go 为什么用两种方法转换相同的值,结果会不同?
将相同常量转换为Go 为什么用两种方法转换相同的值,结果会不同?,go,floating-point,type-conversion,int,Go,Floating Point,Type Conversion,Int,将相同常量转换为float64的两种方法返回相同的值,但当我尝试将这些新值转换为int时,结果不同 ... const Big = 92233720368547758074444444 func needFloat(x float64) float64 { return x } func main() { fmt.Println(needFloat(Big)) fmt.Println(float64(Big)) fmt.Println(int(needFl
float64
的两种方法返回相同的值,但当我尝试将这些新值转换为int
时,结果不同
...
const Big = 92233720368547758074444444
func needFloat(x float64) float64 {
return x
}
func main() {
fmt.Println(needFloat(Big))
fmt.Println(float64(Big))
fmt.Println(int(needFloat(Big)))
fmt.Println(int(float64(Big)))
}
我希望前两个Println
返回相同类型的值
fmt.Println(needFloat(Big)) // 9.223372036854776e+25
fmt.Println(float64(Big)) // 9.223372036854776e+25
因此,当我将它们转换为int
时,我希望得到相同的输出,但是:
fmt.Println(int(needFloat(Big))) // -2147483648
fmt.Println(int(float64(Big))) // constant 92233720368547758080000000 overflows int
如果x可由表示,则常量值x可转换为类型T
T的值
非常量值x可以转换为以下任意类型的T
案例:
-x的类型和T都是整数或浮点类型
如果您真正的问题是为什么一个尝试转换为
int
会产生编译时错误消息,而另一个会产生非常负的整数,那是因为一个是编译时转换,另一个是运行时转换。我认为,在这些情况下,明确你期望的是什么,什么可以运行,什么不能运行是有帮助的。这是您的代码的一个版本,最后的转换被注释掉了。注释它的原因当然是它没有编译
正如,Big
是一个常量,特别是一个非类型的常量。同样,常数x
(任何类型)可以转换为新的不同类型T
当且仅当
x
由类型为T
的值指定
(引用部分来自Uvelichitel linked一节,除了我的添加了单词“representable”的内部链接。)
表达式float64(大)
是一种显式类型转换,其x
为常量,因此结果是具有给定值的float64类型常量。到目前为止,这很好:现在我们有了922337203685477580744444
作为浮动64。这就去掉了一些数字:实际的内部表示是9223372036854775808000000
(请参阅)。低位(…74444444
)已四舍五入为…8000000
。有关舍入的原因,请参见“可表示”链接
表达式int(float64(Big))
是围绕内部显式类型转换的外部显式类型转换。我们已经知道内部类型转换的作用:它生成float64
常量9223372036854775808000000.0
。外部转换尝试将此新值表示为int
,但它不适合,从而产生错误:
./prog.go:18:17: constant 92233720368547758080000000 overflows int
如果注释掉的行未注释。再次注意,由于内部转换,该值已四舍五入
另一方面,needFloat(大)
是一个函数调用。调用该函数会将非类型常量分配给其参数(afloat64
),并获取其返回值(相同的float64
,value9223372036854775808000000.0
。在给定默认或显式格式化指令的情况下,打印所需内容。返回值不是常量
类似地,int(needFloat(大))
调用needFloat
,它返回与以前相同的float64
值,而不是一个常量。int
显式类型转换尝试在运行时而不是在编译时将此值转换为int
。对于数值类型之间的此类转换,在,以及最后一条警告。在这里,规则2适用:任何分数部分都将被丢弃。但警告也适用于:
在所有涉及浮点或复数值的非常量转换中,如果结果类型不能表示值,则转换成功,但结果值取决于实现
换句话说,没有运行时错误,但是您得到的int
值(在本例中为-2147483648
)是允许的最小32位整数,这取决于实现。此特定实现选择使用此特定负数作为其结果。另一个实现可能选择其他值er编号。(有趣的是,在操场上,如果我直接转换成uint
我得到零。如果我转换成int
,然后转换成uint
,我得到我期望的0x8000000。)
因此,在是否得到错误方面的关键区别在于,是在编译时通过常量进行转换,还是在运行时通过运行时转换进行转换。奇怪,如果执行
f:=float64(大);fmt.Println(int(f))
也很有效,因为Big
是一个非类型常量,因此可以根据使用它的上下文将其解释为不同的类型,如规范中所述:
int(needFloat(Big)) //is non-constant expression because of function call
./prog.go:18:17: constant 92233720368547758080000000 overflows int