Go-Rune问题研究
这个问题是当时在测试range的时候写的一个示例:
package main
import "fmt"
func main() {
Chinese_str := "中华民族万岁"
fmt.Print(Chinese_str)
for i, v := range Chinese_str {
fmt.Print(i, Chinese_str[v-1], " ")
}
}
但是输出结果却是
G:\go\awesomeProject\Range
go run Chinese_Example.go
中华民族万岁panic: runtime error: index out of range [20012] with length 18
goroutine 1 [running]:
main.main()
G:/go/awesomeProject/Range/Chinese_Example.go:9 +0x166
exit status 2
问题在于:
- **在 **
Chinese_str[v-1]
中,v 是 rune 类型(Unicode 码点),而不是索引
这里了解一下rune
rune 是 Go 语言中的一种基本数据类型,它是 int32 的别名,用于表示一个 Unicode 码点(code point)。一个 rune 字面量就是一个单引号括起来的字符。
- **直接使用 **
Chinese_str[index]
会得到字节(byte),而不是完整的中文字符 - 中文字符在 UTF-8 编码中占用 3 个字节,不能直接按字节索引访问
rune类型
rune 的重要特性:
- 大小固定:
- rune 总是 4 字节(32位)
- 可以表示任何 Unicode 字符
- 用途:
- 处理 Unicode 字符
- 支持多语言字符(中文、日文、emoji等)
- 字符串遍历和操作
package main
import "fmt"
func main() {
var zhong rune = '中'
//fmt.Println(zhong)
//字符
fmt.Printf("%c\n", zhong)
//Unicode
fmt.Printf("%d\n", zhong)
//16进制
fmt.Printf("%x\n", zhong)
}
---》
G:\go\awesomeProject\data_structure\rune
go run rune1.go
20013
中
20013
4e2d
解决方法
- Go 语言中的字符串是以 UTF-8 编码存储的
package main
import "fmt"
func main() {
Chinese_str := "中华民族万岁"
fmt.Println(Chinese_str)
// 使用 range 遍历字符串
for i, v := range Chinese_str {
fmt.Printf("索引:%d 字符:%c Unicode:%d\n", i, v, v)
}
}
但是输出结果如下:
G:\go\awesomeProject\data_structure\rune
go run rune2.go
中华民族万岁
索引:0 字符:中 Unicode:20013
索引:3 字符:华 Unicode:21326
索引:6 字符:民 Unicode:27665
索引:9 字符:族 Unicode:26063
索引:12 字符:万 Unicode:19975
索引:15 字符:岁 Unicode:2368
索引是三的倍数是由于: 因为每个中文字符在 UTF-8 编码中占用 3 个字节,i 表示字节偏移量,而不是字符位置
为了解决这个问题,我们可以转换成rune切片
package main
import "fmt"
func main() {
Chinese_str := "中华民族万岁"
// 转换为 rune 切片
runes := []rune(Chinese_str)
for i, v := range runes {
fmt.Printf("位置:%d 字符:%c\n", i, v)
}
}
// fmt.Printf("字节长度:%d\n", len(Chinese_str)) 输出字节长度
// fmt.Printf("字符数量:%d\n", len([]rune(Chinese_str))) 输出字符数量
结果如下:
G:\go\awesomeProject\data_structure\rune
go run rune3.go
位置:0 字符:中
位置:1 字符:华
位置:2 字符:民
位置:3 字符:族
位置:4 字符:万
位置:5 字符:岁
others
牢记一个-->"Go语言默认使用 UTF-8 编码,这是 Go 语言的一个重要特性"
下面是一个记录📝
func main() {
const π = 3.14159
fmt.Println(π)
str := "👋 Hello 中国🀄️ 🌍"
fmt.Println(str) // 输出:苹果
}
不知道这样行不行
package main
import "fmt"
func main() {
// emoji 作为变量名
var 😀 = "笑脸"
var 🍎 = "苹果"
fmt.Println(😀) // 输出:笑脸
fmt.Println(🍎) // 输出:苹果
// 甚至可以用作函数名
fmt.Println(say👋("世界")) // 输出:你好,世界
}
func say👋(name string) string {
return "你好," + name
}
但是我没有跑通
还发现了Unicode库检测,挺好玩的
package main
import (
"fmt"
"unicode"
)
func main() {
//Uniocde库使用
var str rune = '中'
fmt.Println("是否为汉字?", unicode.Is(unicode.Han, str))
fmt.Println(string((unicode.ToLower('A'))))
}