Go语言的字符串类型
统一设置为string
:
1 | const ( |
功能特点:
- string类型的数据是不可变的;
- 零值可用;
- 获取长度的时间复杂度是O(1)级别
- 支持通过 +/+= 操作符进行字符串连接
- 支持各种比较关系操作符:==、!=、>=、<=、<、>
- 对非ASCII字符提供原生支持
- 原生支持多行字符串
字符串的内部表示
1 | // $GOROOT/src/reflect/value.go |
string 类型其实是一个“描述符”,它本身并不真正存储字符串数据,而仅是由一个指向底层存储的指针和字符串的长度字段组成的。
string 类型变量在 Go 内存中的存储:
Go 编译器把源码中的 string 类型映射为运行时的一个二元组(Data, Len),真实的字符串值数据就存储在一个被 Data 指向的底层数组中。通过 Data 字段,我们可以得到这个数组的内容。
字符串的高效构造
1 | var sl []string = []string{ |
从基准测试的输入结果的第三列,即每次操作耗时的数值来看:
- 做了预初始化的
strings.Builder
连接构造字符串的效率最高; - 带有预初始化的
bytes.Buffer
和strings.Join
这两种方法效率接近; - 未做预初始化的
strings.Builder
、bytes.Buffer
和操作符连接在第三档次; fmt.Sprintf
性能最差。
结论:
- 在能预估出最终字符串长度的情况下,使用预初始化的
strings.Builder
连接构建字符串效率最高; strings.Join
连接构建字符串的平均性能最稳定;- 使用操作符连接的方式最直观,并且可以得到编译器的优化处理;
fmt.Sprintf
效率不高,但适合由多种不同类型的变量来构建特定格式的字符串。
字符串相关的高效转换
[]rune或[]byte 反向转换为 string:
1 | func main() { |
转换是要付出代价的,根源在于string是不可变的,运行时要为转换后的类型分配新内存。
1 | func byteSliceToString() { |
针对“中国欢迎您,北京欢迎您”这个长度的字符串,在string与byte slice互转的过程中都要有一次内存分配操作。
因此,想要更高效地进行转换,唯一的办法就是减少甚至避免额外的内存分配操作。