2

我正在阅读 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

4

2 回答 2

9

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

我将从我所做的另一个相关答案中获取此插图:

 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,还应该知道什么是 slice


在您链接到的代码中,一个简短的分析表明没有可能的溢出,因为list创建为

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

并且稍后调整为count不能大于len(freq)

list = list[0:count]

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

于 2013-07-06T06:21:12.130 回答
1

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

于 2013-07-06T08:09:35.307 回答