【问题标题】:Is working past the end of a slice idiomatic?在切片惯用语的末尾工作吗?
【发布时间】:2013-07-06 06:18:29
【问题描述】:

我正在阅读 Go 的 compress/flate 包,我发现了这段奇怪的代码 [1]:

n := int32(len(list))
list = list[0 : n+1]
list[n] = maxNode()

在上下文中,list 保证指向一个包含更多数据的数组。这是一个私有函数,所以不能在库外滥用。

对我来说,这似乎是一个可怕的 hack,应该是运行时异常。例如,下面的 D 代码生成 RangeError:

auto x = [1, 2, 3];
auto y = x[0 .. 2];
y = y[0 .. 3];

可以通过以下方式更简单地(并且看起来更安全)滥用切片:

x := []int{1, 2, 3}
y = x[:2]
y = append(y, 4) // x is now [1, 2, 4] because of how append works

但这两种解决方案看起来都非常老套和可怕,恕我直言,它们不应该像它们那样工作。这种事情被认为是惯用的 Go 代码吗?如果是这样,以上哪个是更多惯用的?

[1] - http://golang.org/src/pkg/compress/flate/huffman_code.go#L136

【问题讨论】:

    标签: go slice idioms


    【解决方案1】:

    这不是滥用切片,这只是完美地使用切片是什么:数组上的窗口。

    我会从another related answer I made 那里拿这个插图:

     array : [0 0 0 0 0 0 0 0 0 0 0 0]
     array :  <----   capacity   --->
     slice :     [0 0 0 0]
     slice :      <---- capacity ---> 
    

    当数组大于切片时,当您知道自己没有超出底层数组时,通过扩展一个切片来获取更大的切片是正常和标准的(可以使用cap() 进行验证)。

    关于你给出的错误代码作为例子,是的,这可能很危险,但数组和切片是语言中最基本的结构之一,如果你想避免这样的错误,你必须在使用它们之前理解它们。我个人认为任何 Go 程序员不仅应该知道 API,还应该知道 what are slices


    在您链接到的代码中,一个简短的分析表明,由于 list 被创建为,因此不可能发生溢出

    list := make([]literalNode, len(freq)+1)
    

    后来调整为count,不能大于len(freq)

    list = list[0:count]
    

    人们可能更喜欢更多的 cmets,但由于包含 list = list[0 : n+1] 的函数是私有的并且只能从一个地方调用,它也可能被认为是注释冗长和代码模糊之间的平衡听起来是正确的。有太多 cmets 隐藏代码是痛苦的,任何需要阅读此代码的人都可以像我一样轻松检查没有溢出。

    【讨论】:

    • 您的其他答案也很好。当我第一次遇到这种行为时(参见 D 示例),这种行为让我感到惊讶,而且它对我来说似乎很危险,因为它对调用者做出假设,这就是为什么我认为它很可怕。由于这是库中的私有函数,您会认为这段代码 sn-p 惯用吗?
    • @tjameson 我详细说明了我的答案。关于“惯用”问题,是的,我认为这是惯用的。
    【解决方案2】:

    不可能是运行时异常,因为语言规范规定切片操作的上限是切片的容量,而不是长度。

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 2020-01-05
      • 1970-01-01
      • 2011-08-06
      • 2016-06-05
      • 1970-01-01
      • 2016-11-30
      • 2016-05-13
      • 2021-04-09
      相关资源
      最近更新 更多