byte、rune的真身
byte是uint8类型的别名,表示一个字节;rune是int32类型的别名,表示一个Unicode字符。
引入别名而不直接使用 uint8、int32 是为了更直观的表示字符。[]byte 用于字符串的编码表示以及存储,但不利于单个字符的处理,所以需要 rune 类型。
互相转换
string类型转换为[]byte类型1
2
3
4
5var s = "su微英杰"
bys := []byte(s)
fmt.Printf("type: %T, value: %d", bys, bys)
// type: []uint8, value: [115 117 229 190 174 232 139 177 230 157 176]
// ASCII 字符对应一个字节,中文字符使用了三个字节string转换为[]rune类型1
2
3
4
5var s = "su微英杰"
runs := []rune(s)
fmt.Printf("type: %T, value: %d\n", runs, runs)
// type: []int32, value: [115 117 24494 33521 26480]
// 一个字符对应一个 rune 类型,因此 rune 类型是go语言的字符类型[]byte转string类型1
2
3
4var byslice = []byte{115, 117, 229, 190, 174, 232, 139, 177, 230, 157, 176}
bsliTos := string(byslice)
fmt.Printf("type: %T, value: %q\n", bsliTos, bsliTos)
// type: string, value: "su微英杰"[]rune转string类型1
2
3
4var runeSlice = []rune{115, 117, 24494, 33521, 26480}
runesToS := string(runeSlice)
fmt.Printf("type: %T, value: %q\n", runesToS, runesToS)
// type: string, value: "su微英杰"
使用索引定位字符
可以把 string 类型看做是 byte 数组,那么对于 ASCII 字符来说,可以通过数组索引形式来定位到字符,也可以使用 len(s) 函数获取字符数。
1 | s := "I am a sick." |
如果字符串中含有非 ASCII 字符,因为非 ASCII 字符占用 2-3个字节,所以不能直接使用数组索引来访问某个字符,可以先转换为 []rune 类型。
1 | var s = "su微英杰" |
计算字符串的长度
由ASCII 字符组成的字符串可直接使用 len(s) ,存在非 ASCII 字符的情况下,应当使用 unicode/utf8 包的 RuneCount(p []byte) int 方法和(或)RuneCountInString(s string) int 方法。
前者接受 []byte 类型,后者接受 string 类型
1 | var s = "123go清晨的粥比深夜的酒好喝" |
逐个字符处理
可以对字符串使用 for range 循环遍历处理,每一次循环取得的字符类型为 rune 。下面以将字符串中的空格替换为 %20 为例
1 | func main() { |