模块 4 · 第 4 课(共 5)课程中的19/50~12 min
模块课程(4/5)
字符串、字节和符文
在 Go 中, string 是一个不可变的字节序列。字符串文字
以 UTF-8 编码。 rune 是 int32 的别名,并且
代表单个 Unicode 代码点。
了解字节和符文之间的区别对于 当字符串包含重音符号、表情符号、表意文字或任何内容时避免出现错误 非 ASCII 字符。
string = 字节,而不是字符
Go
s := "ciaò"
fmt.Println(len(s)) // 5 — not 4!
fmt.Println(s[0]) // 99 ('c' as a byte)
fmt.Println(s[3]) // 195 (first byte of 'ò' in UTF-8)len(s) 返回字节的数量,不可见字符。
索引 s[i] 返回第 i 个字节 (uint8),而不是字符。
for range 迭代符文
for i, r := range s 动态解码 UTF-8: i 是字节偏移量
符文开头的 r 是符文 (int32):
Go
s := "ciaò"
for i, r := range s {
fmt.Printf("%d %c (U+%04X)\n", i, r, r)
}
// 0 c (U+0063)
// 1 i (U+0069)
// 2 a (U+0061)
// 3 ò (U+00F2) <- starts at byte 3, takes 2 bytes[]rune(s):每个字符索引
显式转换:分配新的符文片段。成本高昂但是 有时需要:
Go
runes := []rune("ciaò")
fmt.Println(len(runes)) // 4
fmt.Println(string(runes[3])) // òstring(runes) 是逆转换:采用 []rune 并生成
UTF-8 字符串。
字符串是不可变的
Go
s := "ciao"
// s[0] = 'C' // ERROR: cannot assign to s[0]要变异,转换为 []byte 或 []rune,操作,转换回来:
Go
b := []byte(s)
b[0] = 'C'
s = string(b) // "Ciao"级联
+ 运算符有效,但对于循环中的许多串联,请使用
strings.Builder (更高效,避免中间分配):
Go
var sb strings.Builder
for i := 0; i < 5; i++ {
sb.WriteString("ab")
}
fmt.Println(sb.String()) // "ababababab"有用的包
strings:Contains、HasPrefix、Split、Join、ToUpper、Replace...strconv:Atoi、Itoa、ParseFloat、FormatInt...unicode:IsLetter、IsDigit、ToUpper...unicode/utf8:RuneCountInString(替代len([]rune(s)))。
尝试一下
锻炼#go.m4.l4.e1
尝试:0加载中...
使用 %d %c 迭代带有范围的字符串 s 并打印索引和符文。
正在加载编辑器...
显示提示
字符串范围返回字节偏移+符文。
3 次尝试后可用的解决方案
锻炼#go.m4.l4.e2
尝试:0加载中...
将 s 转换为 []rune 并以字符为单位打印其长度。
正在加载编辑器...
显示提示
显式转换:`[]符文`。
3 次尝试后可用的解决方案
Quiz#go.m4.l4.e3
准备好什么是 len("ciaò")?
Go
s := "ciaò"
fmt.Println(len(s))回顾
string= 不可变的字节序列,UTF-8 编码。len(s)= 字节;s[i]= 第 i 个字节 (uint8)。for i, r := range s解码符文;i是字节偏移量。[]rune(s)按字符索引(成本高昂,分配)。- 变异:通过
[]byte或[]rune。 - 在循环中连接:
strings.Builder。 - 关键包:
strings、strconv、unicode、unicode/utf8。