Go语言的数据类型分为:基础、聚合、引用、接口四大分类,本章介绍基础类型中的字符串,以及它们在各个场景下的最佳实践。
1 - 基础类型归类
基础数据类型可分为:数字、布尔类型、字符串。
本章的重点是字符串类型,数字与布尔类型之前已经介绍过。
2 - 字符串存储结构
源码文件 src/runtime/string.go 中定义字符串结构,str 指向底层的字节数组地址,len 读取底层字节数组的长度。
如设置字符串x为:“ops.研究所.cn”,则x、x[2:15] 、底层字节数组y在内存中结构示例
底层字节数组y既为x.str所指向的内存地址,字节数组长度16,字符数量为10,字节类型为byte等同于uint8。
字符串内部是指向不可变的字节数组,也就意味着你只能读取它,而不能更改这个字节数组所对应的值。它可以包含任意内容,如果是文本则按照UTF-8编码进行存储。
图1中字符串x[2]等于”s",如变更它的值为”t"
x := "ops.研究所.cn" x[2] = "t"
编译器会给予错误提示:"cannot assign to x[2]”。
字符串默认值不是nil,而是空字符。
3 - 使用的字符集
最通用的字符编码是ASCII,由1个字节表示,二进制最高位为奇偶校验,剩余7个可编码位,共编码128个字符。
对于世界上其他语言,ASCII编码数量有限,所以才有unicode标准,统一对所有字符进行编码,每个字符均有唯一的编号与其对应。
而utf-8是目前最流行的一个unicode标准实现,Go语言源码必须按照utf-8编码存储,例如在win系统下,使用记事本打开源码文件,变更后存储,也就是文件另存为时,必须是选择以utf8储存,否则编译会出illegal UTF-8 encoding错误提示。
Unicode标准UTF-8实现
unicode规定了每个字符对应的数字编号是多少,没有规定计算机系统如何存储这个编号,而utf-8、utf-16、utf-32则说明它们的存储方式。也就是unicode规定了编号,而utf8实现数据落地存储。
例如utf-32直接使用32位来表示编码,与unicode规定的字符编号对应,这样会导致很多不必要的空间浪费。而utf-8则以字节为单位,各个字符可能占8至32位空间不等,可变长,同时又兼容ASCII。
编码表示转换过程
这里对比“s”、“研” 的unicode码点与utf-8编码字节序转换做个示例,对比单字节与多字节实际在计算机存储系统中所占用的空间。
由上图可见“s”的unicode码点等同于ascii,也就是unicode兼容ascii总的128个编码值。编码值转换16进制既0x73,则对应unicode码点表示为:U+0073。
由上图可见“研”字在unicode编码中对应的码点十进制表示为30740,转为16进制既0x7814,或者表示为:U+7814。
在次强调utf-8是表示如何对这个字符的unicode码点值在计算机系统中进行存储的一种方式,其他还有如:utf-16、utf-32。
”s”使用utf-8编码存储占用1个字节既8位空间,“研”使用utf-8编码存储需占用3个字节24位存储空间,对于不同的字符,utf-8使用不同的存储空间,这也是可变长编码的名称由来。
4 - 基础类库使用
涉及字符串处理的4个基本类库:bytes, strings, strconv, unicode
bytes: 用于处理字节切片([]byte)
strings: 用于基本的字符串处理,如:搜索,替换,查找等
strconv: 用于字符串、布尔值、数字类型,各进制直接的转换
unicode: 用于判断字符类型,如是数字还是字母,大小写,占用多少字节等
5 - 最佳实践分享
大量字符串拼接
如果需要大量进行字符串拼接操作,不要使用运算符”+”进行连接,请使用bytes.Buffer或strings.Builder
运行结果
分别运行基准测试,后面两种字符串拼接方式效率至少高出20倍。
共享底层存储,子字符串并不导致内存分配
由于字符串只读的特性,所以创建子字符串时共享底层数组,不会重新内存分配。
a := “hello, world” m := a[1:5] n := a[2:8]
使用反引号表示正则或HTML模版
如果需表达大量text或html模版等,可以使用反引号进行定义字符串的原始内容
a := `<h3>hello world</h3>`
string、rune与bytes的区别
string转化为[]rune,是unicode码点,此时取长度:len([]rune) 为字符长度。
string转化为[]byte,是utf8编码,此时取长度:len([]byte)和len(string)长度一致,均为字节长度。
运行结果
字节与字符的区别,ascii字符等于字节,1个中文字符可能占用2至4个字节。特别的在for range循环时,迭代的是以字符为单位,所有下标有可能会出现跳跃。