为了账号安全,请及时绑定邮箱和手机立即绑定

符文与字符串范围内的字节

符文与字符串范围内的字节

Go
饮歌长啸 2023-07-31 16:37:57
看起来当我们是range一个字符串时,我们得到的字符是rune类型,但是如果我们通过 获取它str[index],它们将是byte类型,为什么呢?
查看完整描述

3 回答

?
慕哥9229398

TA贡献1877条经验 获得超6个赞

对于第一级,原因是因为这就是语言的定义方式。String类型告诉我们:

字符串值是一个(可能为空)字节序列。字节数称为字符串的长度,并且永远不会是负数。字符串是不可变的:一旦创建,就不可能更改字符串的内容。

和:

字符串的字节可以通过整数索引 0 到 len(s)-1 来访问。

同时,range是一个可以插入到for语句中的子句,并且规范说:

“range”子句右边的表达式称为范围表达式,它可以是... [a] string ...

和:

  1. 对于字符串值,“range”子句从字节索引 0 开始迭代字符串中的 Unicode 代码点。在连续迭代中,索引值将是连续 UTF-8 编码代码点的第一个字节的索引字符串和类型为 的第二个值rune将是相应代码点的值。如果迭代遇到无效的 UTF-8 序列,则第二个值将为0xFFFDUnicode 替换字符,并且下一次迭代将在字符串中前进一个字节。

如果你想知道为什么语言是这样定义的,你真的必须问定义者本身。但是,请注意,如果for仅在字节范围内进行调整,则您需要构建自己的更高级的循环来在符文范围内进行调整。鉴于这for ... range 确实可以通过符文进行操作,如果您通过字符串中的字节进行操作s,您可以编写:

for i := 0; i < len(s); i++ {
    ...
}

并轻松访问s[i]循环内部。你也可以写:

for i, b := range []byte(s) {
}

并在循环内访问索引i和字节。b(从 string 到 的转换[]byte,反之亦然,可能需要一个副本,因为[]byte可以修改。但在这种情况下,range不会修改它,编译器可以优化掉副本。



查看完整回答
反对 回复 2023-07-31
?
慕虎7371278

TA贡献1802条经验 获得超4个赞

只是一个快速而简单的答案,说明为什么以这种方式定义语言。

想想符文是什么。Arune代表一个Unicode码点,可以由多个字节组成,根据编码的不同也有不同的表示形式。

现在想想mystring[i]如果返回 arune而不是 a ,那么这样做意味着什么byte。由于如果不扫描字符串就无法知道每个符文的长度,因此该操作需要每次扫描整个字符串,从而使类似数组的访问需要 O(n) 而不是 O(1)。

mystring[i]如果每次都扫描整个字符串,对于该语言的用户来说是非常违反直觉的,对于语言开发人员来说也更加复杂。这就是为什么大多数编程语言(如 Go、Rust、Python)区分 Unicode 字符和字节,有时仅支持字节索引。

当从字符串的开头迭代时,一次访问一个字符串rune要简单得多,例如使用range. 可以扫描连续的字节并将其分组在一起,直到它们形成可以作为 返回的有效 Unicode 字符rune,然后继续处理下一个字节。


查看完整回答
反对 回复 2023-07-31
?
芜湖不芜

TA贡献1796条经验 获得超7个赞

只是让你知道。如果您想使用经典的 for循环迭代string并使用运算符[]来获取rune,您可以执行以下操作:


{

  rstr := []rune(MyString)

  for idx := 0; idx < len(rstr); idx++ {

    // code before...

    currentRune := rstr[idx]

    _ = currentRune // to avoid unused error

    // code after...

  }

}


查看完整回答
反对 回复 2023-07-31
  • 3 回答
  • 0 关注
  • 86 浏览
慕课专栏
更多

添加回答

举报

0/150
提交
取消
意见反馈 帮助中心 APP下载
官方微信