1
XanderChen 2020-06-29 18:02:33 +08:00
我怎么记得不加类型注解要用 := 来声明变量来着。
另外你把 10 改成 10.0 试试,没准是取决于...emmm.... 因为 10 被隐式声明为整型,你又没声明你需要的数据类型,所以编译器决定给你整型结果? 要不你把 4.0 也做个变量再除一下试试。 |
2
rrfeng 2020-06-29 18:04:29 +08:00
字面量会进行类型推断,变量不需要类型推断,算式中的字面量直接按变量类型来,否则就得做强制类型转换。
大概就是这么回事。 |
3
nidaye999 2020-06-29 18:09:22 +08:00
浮点数不能给整数运算。
|
4
lxy42 2020-06-29 18:13:02 +08:00
你试试 ten / 4.1 大概就知道了
|
5
si 2020-06-29 18:15:51 +08:00 via Android
这种问题直接贴测试代码,大佬一看就清楚了。
|
6
wangbenjun5 OP 我好奇的是为什么这么设计,前后有点矛盾,如果说取决于被除数那 10/4.0 也应该是 2,而不是 2.5 。
唯一能解释通的是,编译器做了类型推断,因为除数是浮点型,所有结果也是浮点数。 |
7
secondwtq 2020-06-29 19:03:45 +08:00
随手看了一下 spec,你这个事 constant expression,有这么一段:
> Any other operation on untyped constants results in an untyped constant of the same kind; that is, a boolean, integer, floating-point, complex, or string constant. If the untyped operands of a binary operation (other than a shift) are of different kinds, the result is of the operand's kind that appears later in this list: integer, rune, floating-point, complex. For example, an untyped integer constant divided by an untyped complex constant yields an untyped complex constant. 大概是为了 大道至简 把 C 里面的类型提升给整过来了。 |
8
favourstreet 2020-06-29 19:12:40 +08:00
@secondwtq 我觉得是反了,压根没整过来才出这种问题。Numeric types 一节里有这样一句话:
> Explicit conversions are required when different numeric types are mixed in an expression or assignment. 意思是必须手动转换类型,所以 C 里面行为明确的类型提升,go 里面变成未定义行为了……,而且按照常量表达式里的那句话,2.5/5 应该等于 0,实际上等于 0.5,这算什么? 所以一个语言有个 ISO 标准的好处就在这里…… |
9
secondwtq 2020-06-29 19:29:15 +08:00
@favourstreet 我觉得设计者的意思是,为了避免类型提升可能存在的问题,于是甩掉了 general 的类型提升,然后为了一点小方便,在 constant expression 这个 special case 里面允许这么做。可能是以为这样不仅 大道至简,还能避免类型提升可能的问题吧(至于类型提升这个东西自身到底应不应该存在?这个问题我推测他们并没有想过)。
结果就出了楼主这个问题。 > 而且按照常量表达式里的那句话,2.5/5 应该等于 0,实际上等于 0.5,这算什么? 我不知道你是怎么看出来的,他还举了例子,integer constant / complex constant = complex constant 。 |
10
favourstreet 2020-06-29 19:49:35 +08:00
@secondwtq 我确实饿极了脑子停转弄错了……我没用过 go 所以去官网上玩了一下 Try Go 发现能重现楼主提到的问题。我另外发现,不同类型变量之间的运算会报编译错误,根据语法还有这些错误提供的线索,我猜编译器可能是这样想的:
ten/4.0 这个表达式里,4.0 是一个常量,神奇的是,常量可以没有类型( untyped )!于是编译器认为转换成整型没有损失信息,还免得编译失败,于是开开心心转成整形了。 |
11
katsusan 2020-06-30 15:31:30 +08:00
golang 的编译大概分为三步,
#1.进行词法分析和语法分析,构建出语法树 AST #2.进行类型检测 typecheck 和 AST 优化(var x = 10/4.0 就在这步计算出来) #3.进行静态单赋值 SSA 优化(ten/4.0 在这步计算得出)和中间代码生成 解析 10/4.0 时,经过一系列 switch case 后会调用[evconst]( https://github.com/golang/go/blob/master/src/cmd/compile/internal/gc/const.go#L569)计算出 10/4.0 写到 x 节点上,而 evaconst 会先调用[match 函数]( https://github.com/golang/go/blob/master/src/cmd/compile/internal/gc/const.go#L686) 来将两个变量转化为同样类型,这个函数逻辑对应着#7 所记录的 spec 规范。 而碰到 print(ten/4.0)时由于左边为变量已经推导出为 int 型所以会被[defaultlit2 函数]( https://github.com/golang/go/blob/master/src/cmd/compile/internal/gc/const.go#L1126)获取并且按左节点优先原则将右边的 4.0 转化为左边的类型。 可以从 GOSSAFUNC=main go build x.go 获得的 html 里看到 main 函数从 source->AST->SSA 的转换过程。 |