Go 语言字符类型本质
在 Go 语言中没有字符类型, 用byte 和 rune 类型表示字符。而在 Go 中, byte 和 rune 类型都是整型的别名,所以字符只是整数的特殊用例。
- Go 语言的字符有以下两种:
- byte 型,其实质是uint8类型,代表一个ASCII码字符。
- rune类型,其实质是int32类型,代表一个 UTF-8字符。因此Go 使用 rune 类型来处理 Unicode。
为什么需要两种类型?
byte 占用一个字节,因此它可以用于表示 ASCII 字符;而 UTF-8 是一种变长的编码方法,字符长度从 1 个字节到 4 个字节不等。byte 显然不擅长这样的表示,就算你想要使用多个 byte 进行表示,你也无从知晓你要处理的 UTF-8 字符究竟占了几个字节。
字符串组成
组成每个字符串的元素叫做“字符”,可以通过遍历或者单个获取字符串元素获得字符。 字符用单引号(’)包裹起来,如:
var a ='s'
var b ='学'
也可利用反引号字符实现多行字符串定义
str := `first line
second line
third line`
fmt.Println(str)
输出:
first line
second line
third line
字面量,操作符和转义
在Go语言中,字符串字面量使用双引号 "" 或者反引号 ' 来创建。双引号用来创建可解析的字符串,支持转义,但不能用来引用多行;反引号用来创建原生的字符串字面量,可能由多行组成,但不支持转义,并且可以包含除了反引号外其他所有字符。双引号创建可解析的字符串应用最广泛,反引号用来创建原生的字符串则多用于书写多行消息,HTML以及正则表达式。
比如下面的这些例子,输出结果完全一致:
text1 := "\"Hello GoLang\",I said"
text2 :=`"Hello GoLang",I said`
常用字符串转义符如下表所示:
| 转义符 | 含义 | |
|---|---|---|
| \r | 回车符(返回行首) | |
| \n | 换行符(直接跳到下一行的同列位置) | |
| \t | 制表符 | |
| \' | 单引号 | |
| \" | 双引号 | |
| \\ | 反斜杠 |
有关字符串的一些基础操作
text1 := "abcdefg"
text1[n] 获取字符串索引位置为n的原始字节,比如a为97
text1[n:m]) 截取得字符串索引位置为 n 到 m-1 的字符串
text1[n:] 截取得字符串索引位置为 n 到 len(s)-1 的字符串
text1[:m] 截取得字符串索引位置为 0 到 m-1 的字符串
utf8.RuneCountInString(text1) 获取字符串字符的个数
[]rune(text1) 将字符串的每一个字符转换为码点值,比如这里会输出[97 98 99 100 101 102 103]
[]byte(text1) 功能同上,但是只适用于ASCII码字符
string(text1[n] 获取字符串索引位置为n的字符值
字符串遍历
方法一:通过每个字符串的下标进行遍历
由于在 Go 语言中,字符串以 UTF-8 编码方式存储,通过下标索引字符串,每次只产生一个字节。因此,如果是ASCII码字符,则每个字符刚好对应一个字节,利用下标可以正常索引;如果字符串中含有 UTF-8 编码字符,例如中文时就会出现乱码,因为在UTF-8一个汉字占3个字节,所以一个汉字将产生三个下标。
s := "hello生活"
for i := 0; i < len(s); i++ {
fmt.Printf("%v(%c) ", s[i], s[i])
}
-----------------------------------------------------------------------
输出:
104(h) 101(e) 108(l) 108(l) 111(o) 231(ç) 148(²) 159(²) 230(æ) 180(´) 187(»)
以上述代码为例,从输出结果可以看出,前面英文部分,一个字母对应一个字节,通过%c也可以获得该值对应的Unicode码值;而后面的汉字,可以看出,两个汉字产生了6个字节,从而在转义的时候出现错误。
方法二:通过for range 进行遍历
range 遍历则会得到 rune 类型的字符,其实质是int32类型,代表一个 UTF-8字符。因此Go 使用 rune 类型来处理 Unicode。
s := "hello生活"
for _, r := range s {
fmt.Printf("%v(%c) ", r, r)
}
-----------------------------------------------------------------------
输出:
104(h) 101(e) 108(l) 108(l) 111(o) 29983(生) 27963(活)
从结果可知,r每次得到一个int32类型( rune 类型)的值,通过%c可以获得该值对应的Unicode码值。
总结:对于ASCII 字符串遍历可以直接使用下标,而对于包含Unicode 字符串遍历用 for range。