2

私は 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) // 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())。

例として挙げたバグのあるコードに関しては、はい、危険かもしれませんが、配列とスライスは言語の最も基本的な構造の1つであり、そのようなバグを回避したい場合は、それらを使用する前に理解する必要があります. 個人的には、go コーダーは API だけでなく、スライスとは何かを知っておく必要があると思います。


listリンク先のコードでは、短い分析では、次のように作成されているため、オーバーフローの可能性がないことが示されています

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

後でサイズ変更されますが、countこれを超えることはできませんlen(freq):

list = list[0:count]

いくつかのコメントを追加した方がよかったかもしれませんが、関数を含む関数list = list[0 : n+1]はプライベートであり、1 つの場所からしか呼び出されないため、コメントの冗長さとコードの不明瞭さのバランスが適切に聞こえると考えられるかもしれません。コードを隠すコメントが多すぎるのは苦痛であり、このコードを読む必要がある人は、私と同じようにオーバーフローがないことを簡単に確認できます。

于 2013-07-06T06:21:12.130 に答える