问题
昨天写代码时,发现了一个我以前没有注意到的 Go 语言特性。
请看下面这一段代码
import "strings"
func someFunc() {
s := "some words"
for i, c := range s {
strings.Contains("another string", c)
}
}
复制代码
这段代码其实是过不了编译的。因为Contains
的签名为func Contains(s, substr string) bool
,而c
的类型已经变成rune
了。
原因
rune
在英语里是符文的意思,玩魔幻RPG游戏的朋友应该很清楚。在 Go 里,一个rune
表示一个 Unicode code point。而 Go 的 for 循环会自动将 string 当作 unicode 来解析,返回的i
是字节位,c
是单个 unicode 字符。
比如下面这段代码(引用自官方文档:golang.org/doc/effecti… )
for pos, char := range "日本\x80語" { // \x80 is an illegal UTF-8 encoding
fmt.Printf("character %#U starts at byte position %d\n", char, pos)
}
复制代码
会打印
character U+65E5 '日' starts at byte position 0
character U+672C '本' starts at byte position 3
character U+FFFD '�' starts at byte position 6
character U+8A9E '語' starts at byte position 7
复制代码
答案
所以说,我的代码有两种改进方法。
方法一
import "strings"
func someFunc() {
s := "some words"
for i, c := range s {
strings.Contains("another string", string(c))
}
}
复制代码
将c
强转回 string。
方法二
import "strings"
func someFunc() {
s := "some words"
for i, c := range s {
strings.ContainsRune("another string", c)
}
}
复制代码
使用ContainsRune
函数。
结语
其实在对付 unicode 这个问题上,在非英语国家工作的程序员会更有经验。我本人很少和其打交道。不过,我很喜欢 Go 对于[]byte
、string
、rune
的设计。这让字符处理变得很容易了。作为曾经的一个 Python2 程序员,我的吐槽还是到位的。
欢迎大家关注我的公众号以及 B 站!