Go语言的字符串底层采用UTF-8编码存储,字符串数组则是多个字符串的集合,在处理这类数据结构时,需要同时掌握数组遍历和UTF-8编码的特性,才能正确获取每个字符的内容。

字符串数组的基础定义
Go语言中的字符串数组是存储多个字符串的复合类型,定义方式和其他数组一致,示例如下:
package main
import "fmt"
func main() {
// 定义一个包含中英文的字符串数组
strArr := []string{"hello", "世界", "Go语言", "test"}
fmt.Println("字符串数组内容:", strArr)
}
UTF-8编码的核心特性
UTF-8是一种变长编码,字符的字节长度根据Unicode码点不同而变化:
- ASCII字符(码点0-127)占用1个字节
- 大部分常用中文、日文等字符占用3个字节
- 部分生僻字符可能占用4个字节
Go语言的string类型本质是只读的字节切片,直接通过下标访问获取的是对应位置的字节值,而不是完整的字符,这也是遍历字符串数组时容易出现问题的核心原因。
字符串数组的两种遍历方式
1. 字节遍历(下标遍历)
通过for循环加下标的方式遍历字符串数组,再对单个字符串做下标访问,获取的是字节值,示例如下:
package main
import "fmt"
func main() {
strArr := []string{"hello", "世界"}
// 遍历字符串数组
for i := 0; i < len(strArr); i++ {
fmt.Printf("第%d个字符串:%sn", i, strArr[i])
// 遍历该字符串的字节
for j := 0; j < len(strArr[i]); j++ {
fmt.Printf("字节下标%d:0x%Xn", j, strArr[i][j])
}
}
}
上述代码中,遍历"世界"字符串时,会输出6个字节值,因为"世"和"界"各占3个UTF-8字节,这种方式无法直接得到完整的字符。
2. 字符遍历(for range遍历)
使用for range遍历字符串时,会自动按照UTF-8编码解析字符,每次迭代返回字符的起始字节下标和对应的rune类型字符值,示例如下:
package main
import "fmt"
func main() {
strArr := []string{"hello", "世界", "Go语言"}
// 遍历字符串数组
for idx, s := range strArr {
fmt.Printf("第%d个字符串:%sn", idx, s)
fmt.Print("字符遍历结果:")
// for range遍历字符串,获取完整字符
for _, r := range s {
fmt.Printf("%c ", r)
}
fmt.Println()
}
}
运行上述代码,会正确输出每个字符串的完整字符,包括中文、英文等混合内容,不会拆分UTF-8的多字节字符。
常见错误与注意事项
在遍历字符串数组时,需要避免以下常见错误:
- 不要直接对字符串数组的元素做下标访问来获取字符,比如
strArr[1][0]获取的是"世界"的第一个字节,不是完整的"世"字符 - 如果需要修改字符串数组中的内容,需要先将字符串转换为rune切片,修改后再转回字符串,因为字符串是不可变的
- 计算字符串长度时,如果需要的是字符数,要使用
utf8.RuneCountInString()函数,而不是len(),len()返回的是字节数
以下是获取字符串数组每个元素的字符数的示例:
package main
import (
"fmt"
"unicode/utf8"
)
func main() {
strArr := []string{"hello", "世界", "Go语言"}
for _, s := range strArr {
byteLen := len(s)
charLen := utf8.RuneCountInString(s)
fmt.Printf("字符串:%s,字节长度:%d,字符长度:%dn", s, byteLen, charLen)
}
}
总结
处理Go语言字符串数组的字符遍历时,要牢记UTF-8的变长编码特性,优先使用for range方式遍历字符串来获取完整字符,避免使用下标直接访问字节。如果需要对字符串内容做修改,要先将字符串转换为rune切片处理,再转回字符串。掌握这些特性后,就能正确处理字符串数组中的各类字符遍历需求,避免出现编码相关的错误。