byte、rune的真身

  • byteuint8 类型的别名,表示一个字节;
  • runeint32 类型的别名,表示一个Unicode字符。

引入别名而不直接使用 uint8int32 是为了更直观的表示字符。[]byte 用于字符串的编码表示以及存储,但不利于单个字符的处理,所以需要 rune 类型。

互相转换

  1. string 类型转换为 []byte 类型

    1
    2
    3
    4
    5
    var 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 字符对应一个字节,中文字符使用了三个字节
  2. string 转换为 []rune 类型

    1
    2
    3
    4
    5
    var 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语言的字符类型
  3. []bytestring 类型

    1
    2
    3
    4
    var 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微英杰"
  4. []runestring 类型

    1
    2
    3
    4
    var 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
2
3
4
5
s := "I am a sick."
s3 := s[3]
slen := len(s)
fmt.Printf("s[3] = %q, slen = %v\n", s3, slen)
// s[3] = 'm', slen = 12

如果字符串中含有非 ASCII 字符,因为非 ASCII 字符占用 2-3个字节,所以不能直接使用数组索引来访问某个字符,可以先转换为 []rune 类型。

1
2
3
4
5
6
var s = "su微英杰"
runs := []rune(s)
runs2 := runs[2]
rlen := len(runs)
fmt.Printf("s[2] = %q, rlen = %v\n", runs2, rlen)
// s[2] = '微', rlen = 5

计算字符串的长度

ASCII 字符组成的字符串可直接使用 len(s) ,存在非 ASCII 字符的情况下,应当使用 unicode/utf8 包的 RuneCount(p []byte) int 方法和(或)RuneCountInString(s string) int 方法。

前者接受 []byte 类型,后者接受 string 类型

1
2
3
4
var s = "123go清晨的粥比深夜的酒好喝"
var slen = utf8.RuneCountInString(s)
fmt.Printf("slen = %v\n", slen)
// slen = 16

逐个字符处理

可以对字符串使用 for range 循环遍历处理,每一次循环取得的字符类型为 rune 。下面以将字符串中的空格替换为 %20 为例

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
func main() {
s := "su微 ddv滴滴 yingjie 年龄 23 age"
newS := replaceSpace(s)
fmt.Println("替换空格后的s:", newS)
}
func replaceSpace(s string) string {
var rs = []rune{}
for _, r := range s { // r为 rune 类型
if r == ' ' {
rs = append(rs, '%', '2', '0')
} else {
rs = append(rs, r)
}
}
return string(rs)
}

// 替换空格后的s: su微%20ddv滴滴%20yingjie%20年龄%2023%20age