首先,我们看一段代码:
const (
x = iota
y
z = "zz"
k
p = iota
)
func main() {
fmt.Println(x, y, z, k, p) // 0 1 zz zz 4
}
为什么会这样?
首先,我们分析 k 为什么是 “zz”?
const 声明有个重要特点,第一个常量必须指定一个表达式,后续的常量如果没有表达式,则继承上面的表达式。这里 k 的前一个表达式为 “zz”,所以 k 的值为 “zz”。
现在,我们再来看看 p 为什么是 4? 其实,这和 go 语言底层的实现有关,const 块中每一行在 Go 中使用 spec 数据结构描述, spec 声明如下:
ValueSpec struct {
Doc *CommentGroup // associated documentation; or nil
Names []*Ident // value names (len(Names) > 0) 保存了一行中定义的常量,如果一行定义 N 个常量,那么 ValueSpec.Names 切片长度即为 N。
Type Expr // value type; or nil
Values []Expr // initial values; or nil
Comment *CommentGroup // line comments; or nil
}
Ident struct {
NamePos token.Pos // identifier position
Name string // identifier name
Obj *Object // denoted object; or nil
}
编译期构造常量的伪代码如下:
for index, value := range ValueSpecs {
for _, ident := range value.Names {
obj := NewConst(ident.name, index, value...) // 此处将 i 值传入,用于构造常量
...
}
}
可以看出,iota 的值其实是通过它的索引推导出来的,即 const 声明块中每新增一行 iota 值自增 1,这里初始化的 iota 为 0,p 的索引为 4,,所以 p 的值为 4。
网友评论