V2EX = way to explore
V2EX 是一个关于分享和探索的地方
现在注册
已注册用户请  登录
assassing
V2EX  ›  程序员

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

  •  
  •   assassing ·
    hxz393 · 117 天前 · 2231 次点击
    这是一个创建于 117 天前的主题,其中的信息可能已经有所发展或是发生改变。

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

    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 语言存在隐式类型转换了。

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

    23 条回复    2024-07-29 20:22:52 +08:00
    lysShub
        1
    lysShub  
       117 天前
    1.5e3 只是一种写法,有小数点不一定是浮点数啊,试试 var b int = 1.55555e3
    MoYi123
        2
    MoYi123  
       117 天前
    1.5e3 这是个字面量, 编译的时候会根据上下文推一个类型出来, 如果推不出来就是 float.
    assassing
        3
    assassing  
    OP
       117 天前
    @lysShub 官方提到指数形式用于表达浮点数,但并没有用于整型的示例,我很迷惑: https://go.dev/ref/spec#Floating-point_literals
    qq316107934
        4
    qq316107934  
       117 天前
    是的,你可以试试把 1.5e3 改成 1.5555e3 ,会报错:cannot use 1.5555e3(untyped float constant 1555.55) as int value in variable declaration 表明存在编译类型转换
    assassing
        5
    assassing  
    OP
       117 天前
    @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
        6
    thinkershare  
       117 天前
    @assassing 要记住,go 的常量没有类型,类型是在使用它的时候确定的。
    assassing
        8
    assassing  
    OP
       117 天前
    @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
        9
    eaglexiang  
       117 天前
    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
        10
    kuro1  
       117 天前
    可以试试
    ```
    func main() {
    const a = 5
    fmt.Printf("%v", a*math.Pi)
    }
    ```
    thinkershare
        11
    thinkershare  
       117 天前   ❤️ 1
    编译器会放松对 untyped 类型的赋值检查。你给出的示例,n 是 untyped int, d 是 untyped float ,但你用参数传递时,它必须要是一个确定类型,此时 untyped float 被推断为默认的浮点类型 float64 ,untyped 的 int 会被推断为 int
    qq316107934
        12
    qq316107934  
       117 天前   ❤️ 1
    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
        13
    assassing  
    OP
       117 天前   ❤️ 1
    @qq316107934 谢谢提供信息,编译器源码我还不太看得懂,先把问题记下来了
    xuld
        14
    xuld  
       117 天前   ❤️ 1
    文档一般是滞后的,不要试图对文档或其他概念咬文嚼字,这是中国人常犯的错误:不必在乎概念或文字上的差异,不必在乎“是否存在隐式类型转换”,是又怎样,不是又怎样。

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

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

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

    go spec 是 go 语义的标准,不是一般的文档,会跟上每个版本变化。细读 go spec 理解语义我觉得是正确的做法
    xuld
        21
    xuld  
       117 天前
    @nagisaushio 你在偷换概念。

    细读 go spec 和咬文嚼字是一个意思吗?

    细读西游记 = 了解每个故事情节、掌握所有人物剧情、分析不同人的行为。

    对西游记咬文嚼字 = 为什么唐僧从出发到西天取经,一路上吃的都是东方的食物,一点西方的食物都没有。
    vx7298
        22
    vx7298  
       117 天前
    var i int=10.0
    var i int=10.2
    assassing
        23
    assassing  
    OP
       117 天前
    @nagisaushio 现在认知是:用指数形式表示的数,是一个不定类型的常量,可能为整数也可能为浮点数。就和下面这种情况一样:

    const c = 1.0
    var d int = c
    关于   ·   帮助文档   ·   博客   ·   API   ·   FAQ   ·   实用小工具   ·   2667 人在线   最高记录 6679   ·     Select Language
    创意工作者们的社区
    World is powered by solitude
    VERSION: 3.9.8.5 · 21ms · UTC 00:17 · PVG 08:17 · LAX 16:17 · JFK 19:17
    Developed with CodeLauncher
    ♥ Do have faith in what you're doing.