type
Post
status
Published
date
Apr 13, 2022
slug
go-bottom-up-book-note-4
summary
Go语言底层原理剖析 第四章 读书笔记
tags
go
note
category
学习笔记
icon
password
书名: Go语言底层原理剖析 基于 Go 1.14 其他链接: 豆瓣链接, 示例源码及勘误

常量

虽然go中变量之间没有隐式类型转换, 但常量是经过精心设计的, 变量与常量之间可以隐式类型转换(仅限untyped, 区别见下)
const c1 = 123 //const c1 untyped int = 123 const c2 int = 123 //const c2 int = 123
" untyped constinterface 是唯二可以做隐式类型转换的类型"
对于大整数和高精度浮点数常量, 为了精确表示, gc会使用math/big处理
常量声明语句的左边是命名常量, 右边是未命名常量, 拥有未定义的类型, 也就是untyped
未命名常量只存在于编译时, 命名常量则存在于内存静态只读区, 不可更改

常量的隐式类型转换

变量以常量声明时

未命名常量声明变量时, 由于其是untyped, 所以可以隐式类型转换为变量的显式类型
命名常量如果是untyped则遵循同样的规则, 如果有显式类型则与普通变量无异
var v1 int = 123 //untyped int转换为int var v2 int = 123.0 //untyped float转换为int //v2的转换可行, 是因为不用截断 //下面这条v3的转换是不可行的 var v3 int = 123.1 //无法对123.1进行截断 var v4 float64 = 1.23 //untyped float转换为float64 var v5 float64 = 1    //untyped int转换为float64
自定义类型与系统内置类型遵循同样规则, 后文同
type myInt int var v1 myInt = 123.0 //untyped float转换为myInt

常量变量运算时

在运算时, 如果两个操作数均是untyped, 则结果的优先级如下:
复数(Imag) > 浮点数(float) > 符文数(rune) > 整数(int)
如果操作数中有显式类型, 隐式类型要转换为与显式类型相同
如果转换时, 出现像var v3 int = 123.1这种无法截断的情况, 一样会报错
var v1 = 3 * 0.3 //v1 类型为float64 const c1 = 3 * 0.3 //c1 类型为untyped float

常量隐式类型转换原理

涉及常量的运算, 都是由gc在编译时的类型检查阶段完成的
compile/internal/gc/const.godefaultlit2函数统一处理, 源码如下:
func defaultlit2(l *Node, r *Node, force bool) (*Node, *Node) { if l.Type == nil || r.Type == nil { return l, r } if !l.Type.IsUntyped() { r = convlit(r, l.Type) return l, r } if !r.Type.IsUntyped() { l = convlit(l, r.Type) return l, r } if !force { return l, r } // Can't mix bool with non-bool, string with non-string, or nil with anything (untyped). if l.Type.IsBoolean() != r.Type.IsBoolean() { return l, r } if l.Type.IsString() != r.Type.IsString() { return l, r } if l.isNil() || r.isNil() { return l, r } k := idealkind(l) if rk := idealkind(r); rk > k { k = rk } t := defaultType(k) l = convlit(l, t) r = convlit(r, t) return l, r }
总的来说, 有显式类型, 则untyped节点转换为该类型
双方都untyped, 则按照常量运算时的优先级决定类型的转换
 
[读书笔记]浮点数与类型推断_Go语言底层原理剖析 第二&三章KeyCastOW选项翻译&解释