Go 语言 for 循环与 string

2,098 阅读1分钟

问题

昨天写代码时,发现了一个我以前没有注意到的 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 对于[]bytestringrune的设计。这让字符处理变得很容易了。作为曾经的一个 Python2 程序员,我的吐槽还是到位的。

space.bilibili.com/16696495

欢迎大家关注我的公众号以及 B 站!