2

我最近问了这个问题,答案增加了我的理解,但他们并没有解决我遇到的实际问题。因此,我将尝试提出一个类似但不同的问题,如下所示。

假设我想访问runea 的随机元素string。一种方法是:

func RuneElement(str string, idx int) rune {
  var ret rune
  for i, c := range str {
    if i == idx {
      return c
    }
  }
  return ret // out of range -> proper handling is needed
}

如果我想多次调用这样的函数怎么办?我想我正在寻找的就像一个运算符/函数str[i](返回 a byte),它返回第 -th 位置的rune元素。i为什么可以使用for ... range但不能通过str.At(i)例如函数访问此元素?

4

1 回答 1

4

stringGo 中的值存储文本的 UTF-8 编码字节序列。这是一个已经做出的设计决定,不会改变。

如果您想rune在任意索引处有效地从中获取 a,则必须对字节进行解码,对此您无能为力(进行for ... range此解码)。没有“捷径”。选择的表示并没有提供开箱即用的功能。

如果您必须经常/多次执行此操作,您应该更改输入而不是使用stringa []rune,因为它是一个切片并且可以有效地被索引。string在 Go 中不是[]runestring在 Go 中实际上是只读的[]byte(UTF-8)。时期。

如果您无法更改输入类型,则可以构建一个映射string到其的内部缓存[]rune

var cache = map[string][]rune{}

func RuneAt(s string, idx int) rune {
    rs := cache[s]
    if rs == nil {
        rs = []rune(s)
        cache[s] = []rune(s)
    }
    if idx >= len(rs) {
        return 0
    }
    return rs[idx]
}

这取决于情况是否值得:如果RuneAt()用一小组strings 调用,这可能会大大提高性能。如果传递的字符串或多或少是唯一的,这将导致更差的性能和大量的内存使用。此外,此实现对于并发使用也不安全。

于 2017-06-13T17:03:06.710 回答