V2EX = way to explore
V2EX 是一个关于分享和探索的地方
现在注册
已注册用户请  登录
The Go Programming Language
http://golang.org/
Go Playground
Go Projects
Revel Web Framework
lizon
V2EX  ›  Go 编程语言

golang 的字面值与类型转换,来猜猜结果

  •  
  •   lizon · 2017-09-08 12:16:38 +08:00 · 2355 次点击
    这是一个创建于 2668 天前的主题,其中的信息可能已经有所发展或是发生改变。
    package main
    
    import "fmt"
    
    func main() {
     a := 1
     b := 3
     
     fmt.Printf("%T\n", a / b)
     fmt.Printf("%T\n", a / 3)
     fmt.Printf("%T\n", a / 3.0)
     fmt.Printf("%T\n", 1 / 3)
     fmt.Printf("%T\n", 1 / 3.0)
    }
    

    答案: https://play.golang.org/p/mgxFyXtzGv

    第 1 条附言  ·  2017-09-08 13:15:06 +08:00
    补充,注意第三个输出
    第 2 条附言  ·  2017-09-08 14:09:48 +08:00

    可能这样效果更明显一些吧

    package main
    
    import "fmt"
    
    func main() {
     a := 1
     
     fmt.Println(a / 3)
     fmt.Println(a / 3.0)
     //fmt.Println(a / 3.1) 类型错误
    }
    

    https://play.golang.org/p/nAD0aFC9re

    我觉得 a / 3.0 的时候编译错误更好,沿用其他语言的习惯这里容易掉坑里

    29 条回复    2017-09-08 19:20:46 +08:00
    sjj050121014
        1
    sjj050121014  
       2017-09-08 12:41:20 +08:00
    感觉没什么特别啊
    sjj050121014
        2
    sjj050121014  
       2017-09-08 12:44:05 +08:00
    不好意思,没看清,确实有特别,变量除小数,居然还是整形
    sjj050121014
        3
    sjj050121014  
       2017-09-08 12:49:04 +08:00
    https://play.golang.org/p/nJs3oLSwyZ 加了个 c:=3.0,这个居然编译错误
    secondwtq
        4
    secondwtq  
       2017-09-08 12:56:35 +08:00 via iPhone
    第一反应:golang 你个浓眉大眼的居然也叛变了

    @sjj050121014 3# 这个才正常
    frye
        5
    frye  
       2017-09-08 13:20:21 +08:00
    没看出来有任何问题,为啥这么大惊小怪?
    Kisesy
        6
    Kisesy  
       2017-09-08 13:23:06 +08:00
    var a int = 3.0
    fmt.Println(a)

    楼主是想说这个?
    topbandit
        7
    topbandit  
       2017-09-08 13:25:16 +08:00
    为神马会这样?
    fwee
        8
    fwee  
       2017-09-08 13:27:04 +08:00
    看来编译器对 int 字面量有特殊的转换处理... 不过 go 本来就不是很严谨的语言,一直没搞懂怎么优雅的提供一个 bool 的饮用
    kofj
        9
    kofj  
       2017-09-08 13:29:29 +08:00
    @Kisesy 没准儿 Po 主真这么想的
    XIVN1987
        10
    XIVN1987  
       2017-09-08 13:34:54 +08:00
    为啥会这样??谁能解释一下!
    rrfeng
        11
    rrfeng  
       2017-09-08 13:35:19 +08:00
    var a int
    var b float

    a / b -> type error

    在算式中的字面量会按照算式其他变量的类型进行 cast,而不是字面量的默认类型。

    ```
    type A int

    func main() {
    var a A
    a = 10
    fmt.Printf("%T\n", a/"abc")
    fmt.Printf("%T\n", a/3.0)
    }
    ```
    rrfeng
        12
    rrfeng  
       2017-09-08 13:37:15 +08:00
    可以说是在不同的操作符(复制操作、运算操作)下,对字面量进行类型判定的方式是不一样的。

    这没有任何问题,并不是对 int 有特殊处理。

    哪里的出来的 go 不是很严谨的语言……
    88250
        13
    88250  
       2017-09-08 13:40:49 +08:00
    gamexg
        14
    gamexg  
       2017-09-08 14:27:31 +08:00 via Android
    golang 不会进行自动的类型转换,整数只能除以整数,不会自动转换成为浮点数,字面量类型是根据所在位置来决定的。

    第三个位置需要一个整数,3.0 是合法的整数,没有报错。附言里面的 3.1 不是合法整数,炸了正常。

    运行结果看起来符合预期。
    rrfeng
        15
    rrfeng  
       2017-09-08 15:38:18 +08:00
    本质上是 var a int = 3.0 是一个合法的操作。
    这点去别的语言对比一下看看吧。
    jadeity
        16
    jadeity  
       2017-09-08 16:32:48 +08:00
    3.0 从数学上来说应该是整数吧?有些语言把带小数点的字面量当成浮点型,go 在这个地方当成整数。也说不上谁对谁错,习惯不一样。
    kiddult
        17
    kiddult  
       2017-09-08 16:51:56 +08:00
    @jadeity 极少会有把 3.0 当整数的语言吧,a / 3.0 和 1 / 3.0 结果不一样有点反应不过来
    Yoock
        18
    Yoock  
       2017-09-08 16:55:25 +08:00
    go 所有的类型转换都需要是显示的,所以报错也很正常。
    jadeity
        19
    jadeity  
       2017-09-08 17:01:04 +08:00
    @kiddult 我印象中 go 这个语言好像特别重视格式这方面的内容,要让这些“习惯”“失效”。
    lizon
        20
    lizon  
    OP
       2017-09-08 18:06:16 +08:00 via Android
    @rrfeng 我希望 a / 3.0 的时候报类型错误,也不要把 3.0 不声不响的当成 int 处理
    rrfeng
        21
    rrfeng  
       2017-09-08 18:13:59 +08:00
    @lizon
    前面说的很明白了,字面量要确定类型的时候跟其所处的位置有关
    https://play.golang.org/
    报错是: cannot convert "a" to type A

    并不是把 3.0 不声不响的当作 int 处理,而是因为算式中的另外一个操作数是 int 类型。

    体会一下:
    var a string = "haha"
    a + 3.0 //报什么错?

    规则就是:如果算式中有一个操作数是字面量,那么就根据另一个操作数的类型来 cast,成功就计算,不成功就报错。
    xrlin
        22
    xrlin  
       2017-09-08 18:20:26 +08:00
    golang 的字面值是没有类型的,赋值或者运算操作才判断类型,不过这确实有点不符合大部分语言的逻辑。
    keenwon
        23
    keenwon  
       2017-09-08 18:25:50 +08:00
    https://play.golang.org/p/0daSoPmuEo

    这样就清净了

    本来就是强类型语言,是 int 就是 int,是 float 就是 float。
    lizon
        24
    lizon  
    OP
       2017-09-08 18:28:55 +08:00
    @rrfeng
    a := 3.0
    fmt.Printf("%T\n", a)
    推导 a 的类型为 float64
    https://play.golang.org/p/0VEgW1QOgk

    这里 cast 为 float 的依据呢
    reus
        25
    reus  
       2017-09-08 18:38:04 +08:00
    没什么奇怪的,po 主不知道 go 里 const 的概念吧。

    3.0 是 const,需要是 int,就转换成 int,需要是 float64,就转换成 float64。
    reus
        26
    reus  
       2017-09-08 18:43:11 +08:00   ❤️ 1
    https://golang.org/ref/spec#Constants

    有明确的规范的,untyped constant 这个概念很多语言都没有。
    rrfeng
        27
    rrfeng  
       2017-09-08 18:43:38 +08:00
    赋值操作符下的 cast
    其他操作符下的 cast

    为什么会觉得这两者应该一样呢?
    lizon
        28
    lizon  
    OP
       2017-09-08 19:18:14 +08:00
    @rrfeng 为什么应该不一样呢?

    既然通过赋值语句能推导出类型,那这个字面值本身就蕴含一个类型

    3.0 在任何情况下的推导类型应该保持一致,而不应该随环境的变化而变化

    a := 1

    a / int(3.0)才应该编译通过,a / 3.0 应该报错
    lizon
        29
    lizon  
    OP
       2017-09-08 19:20:46 +08:00
    @reus 官方解释了就行,我指出来就是觉得这里反直觉,容易掉坑
    关于   ·   帮助文档   ·   博客   ·   API   ·   FAQ   ·   实用小工具   ·   1312 人在线   最高记录 6679   ·     Select Language
    创意工作者们的社区
    World is powered by solitude
    VERSION: 3.9.8.5 · 28ms · UTC 17:52 · PVG 01:52 · LAX 09:52 · JFK 12:52
    Developed with CodeLauncher
    ♥ Do have faith in what you're doing.