Hen*_*yTK 2 string unicode for-loop utf-8 go
我正在阅读Effective Go 文档中关于for语句的部分,并遇到了这个例子:
for pos, char := range "??\x80?" {
fmt.Printf("Character %#U, at position: %d\n", char, pos)
}
Run Code Online (Sandbox Code Playgroud)
输出是:
Character U+65E5 '?', at position: 0
Character U+672C '?', at position: 3
Character U+FFFD '?', at position: 6
Character U+8A9E '?', at position: 7
Run Code Online (Sandbox Code Playgroud)
我不明白的是为什么位置是 0、3、6 和 7。这告诉我第一个和第二个字符长 3 个字节,“替换符文”(U + FFFD)长 1 个字节,我接受和理解。但是,我认为rune是int32类型,因此每个是 4 个字节,而不是 3 个。
为什么某个范围内的位置与每个值应该消耗的内存总量不同?
string在Go值存储为只读字节切片([]byte),其中,字节是(的UTF-8编码的字节rune的多个)string。UTF-8是一种变长编码,不同的 Unicode 码位可能使用不同的字节数进行编码。例如,范围内的值0..127被编码为单个字节(其值是 unicode 代码点本身),但大于 127 的值使用超过 1 个字节。该unicode/utf8包包含与 UTF-8 相关的实用程序函数和常量,例如utf8.UTFMax报告有效 Unicode 代码点在 UTF-8 编码中可能“占用”的最大字节数(即 4)。
这里要注意一件事:并非所有可能的字节序列都是有效的UTF-8 序列。Astring可以是任何字节序列,即使是那些无效的 UTF-8 序列。例如,该string值"\xff"表示无效的 UTF-8 字节序列,有关详细信息,请参阅如何在 Go 中表示可选字符串?
所述for range构建体-当施加在string以上的符文值-迭代string:
对于字符串值,“range”子句从字节索引 0 开始迭代字符串中的 Unicode 代码点。在连续迭代中,索引值将是连续 UTF-8 编码代码点的第一个字节的索引字符串和第二个类型
rune的值将是相应代码点的值。如果迭代遇到无效的 UTF-8 序列,则第二个值将是0xFFFDUnicode 替换字符,下一次迭代将在字符串中前进一个字节。
该for range构造可能会产生 1 或 2 个迭代值。使用 2 时,就像在您的示例中一样:
for pos, char := range "??\x80?" {
fmt.Printf("Character %#U, at position: %d\n", char, pos)
}
Run Code Online (Sandbox Code Playgroud)
对于每次迭代,pos将是符文/字符的字节索引,char并将是string. 正如你在上面的引用中看到的,如果string是一个无效的 UTF-8 字节序列,当遇到一个无效的 UTF-8 序列时,char将是0xFFFD(Unicode 替换字符),并且for range构造(迭代)将推进一个单一的仅字节。
总结一下:位置总是rune当前迭代的字节索引(或者更具体地说:当前迭代的UTF-8编码序列的第一个字节的字节索引rune),但如果无效UTF-遇到8个序列,位置(索引)在下一次迭代中只会增加1。
如果您想了解有关该主题的更多信息,则必须阅读博客文章: