Go 语言存在隐式类型转换?

57 天前
 assassing

忘了在哪本书上看到的例子:

package main

import "fmt"

func main() {
	// 不指定类型时为浮点数
	var a = 2e3
	fmt.Printf("%T: %v\n", a, a) // 输出:float64: 2000

	// 编译成功,因为 1.5e3 等于 1500 ,是一个整数
	var b int = 1.5e3
	fmt.Printf("%T: %v\n", b, b) // 输出:int: 1500
}

上面代码中,为什么 var b int = 1.5e3 能通过编译,难道科学计数法被视为算术表达式或常量表达式?不然我只能认为 Go 语言存在隐式类型转换了。

有请知道的大佬解答原因,还有没有类似的情况呢?

2158 次点击
所在节点    程序员
23 条回复
lysShub
57 天前
1.5e3 只是一种写法,有小数点不一定是浮点数啊,试试 var b int = 1.55555e3
MoYi123
57 天前
1.5e3 这是个字面量, 编译的时候会根据上下文推一个类型出来, 如果推不出来就是 float.
assassing
57 天前
@lysShub 官方提到指数形式用于表达浮点数,但并没有用于整型的示例,我很迷惑: https://go.dev/ref/spec#Floating-point_literals
qq316107934
57 天前
是的,你可以试试把 1.5e3 改成 1.5555e3 ,会报错:cannot use 1.5555e3(untyped float constant 1555.55) as int value in variable declaration 表明存在编译类型转换
assassing
57 天前
@MoYi123 我也偏向于认为 1.5e3 是个字面量,应该说默认推断类型就是 float64:

```
package main

import (
"fmt"
)

func main() {
const n = 5000000

const d = 3e6 + n
fmt.Println(d) // 输出:8e+06
fmt.Printf("%T\n", d) // 输出:float64
}
```
所以和无类型常量计算结果也是 float64 。
然后把指数形式的浮点数赋值给整数:`var b int = 1.5555e3`,编译器报错信息是:`constant 1555.5 truncated to integer`?不知道怎么理解
thinkershare
57 天前
@assassing 要记住,go 的常量没有类型,类型是在使用它的时候确定的。
qq316107934
57 天前
assassing
57 天前
@qq316107934 换了 1.22 版本报错就是这个:`cannot use 1.5555e3 (untyped float constant 1555.5) as int value in variable declaration (truncated)`
我试了 1.5 版本,`var b int = 1.5e3` 也是能通过编译的。只是差一个官方说明,说好了必须要显式转换类型呢?
eaglexiang
57 天前
https://go.dev/ref/spec#Constants

> A constant may be given a type explicitly by a constant declaration or conversion, or implicitly when used in a variable declaration or an assignment statement or as an operand in an expression.
kuro1
57 天前
可以试试
```
func main() {
const a = 5
fmt.Printf("%v", a*math.Pi)
}
```
thinkershare
57 天前
编译器会放松对 untyped 类型的赋值检查。你给出的示例,n 是 untyped int, d 是 untyped float ,但你用参数传递时,它必须要是一个确定类型,此时 untyped float 被推断为默认的浮点类型 float64 ,untyped 的 int 会被推断为 int
qq316107934
57 天前
https://go.dev/ref/spec#Variable_declarations

If that value is an untyped constant, it is * first implicitly converted to its default type* ; if it is an untyped boolean value, it is first implicitly converted to type bool.

官方对无类型常量还是有说明的
assassing
57 天前
@qq316107934 谢谢提供信息,编译器源码我还不太看得懂,先把问题记下来了
xuld
57 天前
文档一般是滞后的,不要试图对文档或其他概念咬文嚼字,这是中国人常犯的错误:不必在乎概念或文字上的差异,不必在乎“是否存在隐式类型转换”,是又怎样,不是又怎样。

go 语言设计之初为了简单,决定不加入隐式类型转换。

多数情况这个决定没有问题,但有一个例外,就是楼主所发现的问题,原本在 C 语言里,因为存在隐式类型转换,这么写毫无违和感。但 Go 现在没隐式类型转换了,这样写会不会报错?

所以最终的结论是看作者要不要对这个场景特殊处理。至于它到底是不是隐式类型转换,连作者都不在乎。他只知道这种写法有可能用到,编译器应该能处理。
assassing
57 天前
@thinkershare 作为常量是可以解释得通,那么下次看到 e 还得心算一下,结果是不是个小数
assassing
57 天前
@kuro1 math.Pi 是个明确的 float64 ,没有争议
rrfeng
57 天前
字面量类型比较灵活。
assassing
57 天前
@xuld 谢谢忠告,咱只想心里有个底,不然看到指数形式就默认是浮点数了。既然没问题就放心用
nagisaushio
57 天前
@assassing 字面常量是**任意精度**的数,没有浮点与否之分。当字面常量赋给有类型变量时,会根据该类型的约束作检查(范围?是否支持小数?)并决定是否报错
nagisaushio
57 天前
@xuld > 文档一般是滞后的,不要试图对文档或其他概念咬文嚼字

go spec 是 go 语义的标准,不是一般的文档,会跟上每个版本变化。细读 go spec 理解语义我觉得是正确的做法

这是一个专为移动设备优化的页面(即为了让你能够在 Google 搜索结果里秒开这个页面),如果你希望参与 V2EX 社区的讨论,你可以继续到 V2EX 上打开本讨论主题的完整版本。

https://www.v2ex.com/t/1060942

V2EX 是创意工作者们的社区,是一个分享自己正在做的有趣事物、交流想法,可以遇见新朋友甚至新机会的地方。

V2EX is a community of developers, designers and creative people.

© 2021 V2EX