工作在切片的末尾之后是否符合惯用法?

huangapple go评论82阅读模式
英文:

Is working past the end of a slice idiomatic?

问题

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

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

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

对我来说,这似乎是一个可怕的黑客技巧,应该引发运行时异常。例如,以下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) // 由于append的工作方式,x现在是[1, 2, 4]

但是这两种解决方案都似乎非常不正规和可怕,我个人认为它们不应该像它们现在这样工作。这种情况被认为是Go代码的惯用写法吗?如果是这样,上述两种解决方案中哪一种更符合惯用写法?

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

英文:

I was reading through Go's compress/flate package, and I found this odd piece of code 1:

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

In context, list is guaranteed to be pointing to an array with more data after. This is a private function, so it can't be misused outside the library.

To me, this seems like a scary hack that should be a runtime exception. For example, the following D code generates a RangeError:

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

Abusing slices could be done more simply (and also look more safe) with the following:

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

But both solutions seem very hacky and scary and, IMHO, should not work as they do. Is this sort of thing considered idiomatic Go code? If so, which of the the above is more idiomatic?

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

答案1

得分: 9

这不是滥用切片,而是完美地使用了切片的特性:切片是数组上的一个窗口。

我会借用我之前回答的一个相关问题的例子:

 数组:[0 0 0 0 0 0 0 0 0 0 0 0]
 数组:  <----   容量   --->
 切片:    [0 0 0 0]
 切片:     <---- 容量 --->

当数组大于切片时,通过扩展一个切片来取得更大的切片是正常和标准的做法,前提是你知道不会超出底层数组的范围(可以使用cap()进行验证)。

关于你提供的有问题的代码示例,是的,它可能是危险的,但数组和切片是语言中最基本的结构之一,如果你想避免这样的错误,你必须在使用它们之前先理解它们。我个人认为,任何Go程序员不仅应该了解API,还应该了解切片的是什么

在你提供的代码中,简短的分析表明,由于list是这样创建的:

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

并且后来被调整大小为count,而count不会大于len(freq)

list = list[0:count]

可能更好的做法是增加一些注释,但由于包含list = list[0 : n+1]的函数是私有的,并且只从一个地方调用,所以可以认为在注释冗长和代码晦涩之间取得了平衡。过多的注释会掩盖代码,任何需要阅读此代码的人都可以轻松地检查是否存在溢出,就像我所做的一样。

英文:

This is not abusing the slice, this is just perfectly using what a slice is : a window over an array.

I'll take this illustration from another related answer I made :

 array : [0 0 0 0 0 0 0 0 0 0 0 0]
 array :  &lt;----   capacity   ---&gt;
 slice :     [0 0 0 0]
 slice :      &lt;---- capacity ---&gt; 

When the array is greater than the slice it's normal and standard to take a greater slice by extending one when you know you don't go out of the underlying array (which can be verified using cap()).

Regarding your buggy code you give as example, yes, it might be dangerous, but arrays and slices are among the most basic structures of the languages and you must understand them before you use them if you want to avoid such bugs. I personally think that any go coder should not only know the API but also what are slices.


In the code you link to, a short analysis shows that there is no possible overflow possible as list is created as

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

and is later resized to count which can't be greater than len(freq) :

list = list[0:count]

One might have preferred a few more comments but as the function containing list = list[0 : n+1] is private and called from only one place, it might also be considered the balancing between comment verbosity and code obscurity sounds right. It's painful to have too much comments hiding the code and anybody in need to read this code is able to easily check there is no overflow just like I did.

答案2

得分: 1

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

英文:

It cannot be a run time exception because the language specification prescribes that the upper limit of the slice operation is the capacity of the slice, not its length.

huangapple
  • 本文由 发表于 2013年7月6日 14:18:29
  • 转载请务必保留本文链接:https://go.coder-hub.com/17500282.html
匿名

发表评论

匿名网友

:?: :razz: :sad: :evil: :!: :smile: :oops: :grin: :eek: :shock: :???: :cool: :lol: :mad: :twisted: :roll: :wink: :idea: :arrow: :neutral: :cry: :mrgreen:

确定