一. string
- golang中对string的解释:
- 8比特字节的集合
- 可以为空(长度为0),但不会是nil
- string对象不可以修改
- 查看string 数据结构: string数据结构跟切片有些类似,例如byte切片,只不过切片还有一个表示容量的成员
//src/runtime/string.go:stringStruct
type stringStruct struct {
//字符串的首地址
str unsafe.Pointer
//字符串的长度
len int
}
- string 拼接源码
// 生成一个新的string,返回的string和切片共享相同的空间
func rawstring(size int) (s string, b []byte) {
p := mallocgc(uintptr(size), nil, false)
stringStructOf(&s).str = p
stringStructOf(&s).len = size
*(*slice)(unsafe.Pointer(&b)) = slice{p, size, size}
return
}
其它问题
- string为什么是不可修改的: Go的实现中string不包含内存空间,只有一个内存的指针,好处是string变得非常轻量,可以很方便的进行传递而不用担心内存拷贝, 因为string通常指向字符串字面量,而字符串字面量存储位置是只读段,而不是堆或栈上,所以才有了string不可修改的约定
- []byte转换成string一定会拷贝内存吗: byte切片转换成string时并不会拷贝内存,而是直接返回一个string,这个string的指针(string.str)指向切片的内存
二. iota
几个小问题
- 下方每个常量值是多少: iota初始值为0,也即LOG_EMERG值为0,下面每个常量递增1
type Priority int
const (
LOG_EMERG Priority = iota
LOG_ALERT
LOG_CRIT
LOG_ERR
LOG_WARNING
LOG_NOTICE
LOG_INFO
LOG_DEBUG
)
- 下方每个常量值是多少:
mutexLocked = 1, mutexWoken =2;mutexStarving = 4;mutexWaiterShift = 3;starvationThresholdNs =1000000
const (
mutexLocked = 1 << iota // mutex is locked
mutexWoken
mutexStarving
mutexWaiterShift = iota
starvationThresholdNs = 1e6
)
- 下方每个常量值是多少:
bit0 = 1, mask0 = 0, bit1 = 2, mask1 = 1, bit3 = 8, mask3 = 7
const (
bit0, mask0 = 1 << iota, 1<<iota - 1
bit1, mask1
_, _
bit3, mask3
)
- 根据以上问题引出iota的定义: iota代表了const声明块的行索引(下标从0开始)
const (
bit0, mask0 = 1 << iota, 1<<iota - 1 //const声明第0行,即iota==0
bit1, mask1 //const声明第1行,即iota==1, 表达式继承上面的语句
_, _ //const声明第2行,即iota==2
bit3, mask3 //const声明第3行,即iota==3
)
第0行的表达式展开即bit0, mask0 = 1 << 0, 1<<0 - 1,所以bit0 == 1,mask0 == 0;
第1行没有指定表达式继承第一行,即bit1, mask1 = 1 << 1, 1<<1 - 1,所以bit1 == 2,mask1 == 1;
第2行没有定义常量
第3行没有指定表达式继承第一行,即bit3, mask3 = 1 << 3, 1<<3 - 1,所以bit0 == 8,mask0 == 7
原理
- const块中每一行在GO中使用spec数据结构描述,spec声明如下
ValueSpec struct {
Doc *CommentGroup // associated documentation; or nil
Names []*Ident // value names (len(Names) > 0)
Type Expr // value type; or nil
Values []Expr // initial values; or nil
Comment *CommentGroup // line comments; or nil
}
- 当前只关注ValueSpec.Names,该切片中保存了一行中定义的常量,如果一行定义N个常量,那么ValueSpec.Names切片长度即为N, const块实际上是spec类型的切片,用于表示const中的多行, 伪代码,可以清晰的看出iota实际上是遍历const块的索引,每行中即便多次使用iota,其值也不会递增
for iota, spec := range ValueSpecs {
for i, name := range spec.Names {
obj := NewConst(name, iota...) //此处将iota传入,用于构造常量
...
}
}