4

以下のコード スニペットは、プライオリティ キューのプッシュ メソッドのライブラリ実装です。a = a[0 : n+1]コードのある行が範囲外エラーをスローしないのはなぜだろうと思っています。

 func (pq *PriorityQueue) Push(x interface{}) {
    // Push and Pop use pointer receivers because they modify the slice's length,
    // not just its contents.
    // To simplify indexing expressions in these methods, we save a copy of the
    // slice object. We could instead write (*pq)[i].
    a := *pq
    n := len(a)
    a = a[0 : n+1]
    item := x.(*Item)
    item.index = n
    a[n] = item
    *pq = a
}
4

4 に答える 4

3

スライスは配列ではありません。これは、既存の配列に対するビューです。問題のスライスは、それ自体より大きい配列によって支えられています。既存のスライスのスライスを定義すると、実際には基になる配列がスライスされますが、参照されるインデックスはソース スライスに対して相対的です。

それは一口です。これを次の方法で証明しましょう: 長さゼロのスライスを作成しますが、基になる配列を強制的に大きくします。でスライスを作成する場合make、3 番目のパラメーターは基になる配列のサイズを設定します。この式make([]int, 0, 2)はサイズ 2 の配列を割り当てますが、サイズ 0 のスライスに評価されます。

package main

import ("fmt")

func main() {
    // create a zero-width slice over an initial array of size 2
    a := make([]int, 0, 2)
    fmt.Println(a)

    // expand the slice.  Since we're not beyond the size of the initial
    // array, this isn't out of bounds.
    a = a[0:len(a)+1]

    a[0] = 1
    fmt.Println(a)
    fmt.Println(a[0:len(a)+1])
}

ここを参照してください。キーワードを使用してcap、特定のスライスをサポートする配列のサイズを参照できます。

あなたが尋ねた特定のコードcap(pq)は、呼び出しコンテキストでループします (container/heap/example_test.go 行 90)。呼び出しサイトでコードを変更し、別のアイテムをキューにプッシュしようとすると、予想どおりにパニックが発生します。私は...おそらく、このようなコードを書くことはお勧めしません。標準ライブラリのコードは実行されますが、自分のコードベースでそれを見つけたら非常に残念です。通常は、appendキーワードを使用する方が安全です。

于 2013-02-03T16:55:16.390 に答える
2

特定のサンプルプログラムで動作するためです。元の/完全なサンプルソースからの重要な部分は次のとおりです)

const nItem = 10

pq := make(PriorityQueue, 0, nItem)

for i := 0; i < cap(pq); i++ {
        item := &Item{
                value:    values[i],
                priority: priorities[i],
        }
        heap.Push(&pq, item)
}
于 2013-02-03T16:56:42.200 に答える
1

container/heapの例ですか? はいの場合、容量が十分に大きいため、例外はスローされません (Pushメソッドの使用方法を参照してください)。例をPush容量よりも多くのアイテムに変更すると、スローされます。

于 2013-02-03T16:57:00.710 に答える
0

一般的にはそうです。例にはありませんcontainer/heap。これは、私が以前に提供した一般的な修正です。

func (pq *PriorityQueue) Push(x interface{}) {
    a := *pq
    n := len(a)
    item := x.(*Item)
    item.index = n
    a = append(a, item)
    *pq = a
}

Project Eulerの問題に対するGolangの解決策 #81

于 2013-02-03T17:05:53.030 に答える