31

http://play.golang.org/p/j-Y0mQzTdP

package main

import "fmt"

type UselessStruct struct {
    a int
    b int
}

func main() {
    mySlice := make([]*UselessStruct, 5)
    for i := 0; i != 5; i++ {
        mySlice = append(mySlice, &UselessStruct{})
    }

    fmt.Println(mySlice)
}

出力:[<nil> <nil> <nil> <nil> <nil> 0xc010035160 0xc010035170 0xc010035180 0xc010035190 0xc0100351a0]

私がしたいのは、ポインターとして保存された5つの UselessStructs にメモリを事前に割り当てることです。構造体値 eq のスライスを宣言すると:

mySlice := make([]UselessStruct, 5)

次に、これにより5つの空の構造体が作成されます-追加は空の構造体を置き換えませんが、代わりにスライスに追加し続けるため、最終結果は次のコードになります:

http://play.golang.org/p/zBYqGVO85h

package main

import "fmt"

type UselessStruct struct {
    a int
    b int
}

func main() {
    mySlice := make([]UselessStruct, 5)
    for i := 0; i != 5; i++ {
        mySlice = append(mySlice, UselessStruct{})
    }

    fmt.Println(mySlice)
}

は:[{0 0} {0 0} {0 0} {0 0} {0 0} {0 0} {0 0} {0 0} {0 0} {0 0}]

スライスを事前に割り当てて埋めるための慣用的な方法は何ですか?

4

4 に答える 4

45

最初の例では、次のようにします。

mySlice := make([]*UselessStruct, 5)
for i := range mySlice {
     mySlice[i] = new(UselessStruct)
}

両方の例で直面している問題は、既に正しい長さのスライスに追加していることです。を設定mySlice := make([]*UselessStruct, 5)すると、長さ 5 の nil ポインターのスライスが要求されます。ポインターを 1 つ追加すると、長さ 6 になります。

代わりに、 を使用しますmySlice := make([]*UselessStruct, 0, 5)。これにより、長さが 0 で容量が 5 のスライスが作成されます。追加するたびに、長さが 1 つ追加されますが、スライスの容量を超えるまで再割り当てされません。

mySlice := make([]*UselessStruct, 0, 5)
for i := 0; i != 5; i++ {
    mySlice = append(mySlice, &UselessStruct{})
}
// mySlice is [0xc010035160 0xc010035170 0xc010035180 0xc010035190 0xc0100351a0]

どちらの例も期待どおりに機能しますが、純粋にスタイル上の理由から最初の例をお勧めします。

于 2013-06-04T00:01:51.187 に答える
9

これには 2 つの方法があります。1 つは、前に行ったようにスロットを事前に割り当てることです。ただし、 を使用する代わりにappend、既存のスロットの 1 つにインデックスを付けるだけです。

mySlice[i] = &UselessStruct{}

2 つ目は、 の「オーバーロードされた」バージョンを使用することですmake。長さゼロを指定しますが、容量は 5 です。

package main

type T struct {
    A int
    B int
}

func main() {
    mySlice := make([]*T, 0, 5)
    for i := 0; i < 5; i++ {
        mySlice = append(mySlice, &T{1, 2})
    }
}

mySlice := make([]*T, 0, 5)長さゼロでスライスを初期化しますが、それでも 5 つのエントリに十分なスペースを事前に割り当てます。

于 2013-06-03T23:27:34.967 に答える
3

本当にポインタが必要ですか?構造体の値はゼロなので、次のようになります。

mySlice := make([]UselessStruct, 5) # has memory preallocated for 5 UselessStructs.

また、スライスは参照型であるため、これら 5 つの UselessStructs への 5 つのポインターを効果的に持つことができます。

渡すために個々の構造体への参照を取得する必要がある場合は、そうすることができます

myStruct := &mySlice[0]

これで、必要に応じて使用する UseLessStruct へのポインターができました。これは、あなたが持っているよりもはるかに少ないコードであり、Go のゼロ値機能を活用しています。

于 2013-06-03T22:15:11.200 に答える
1

最後に: append は nil スライスで機能するため、make でスライスを作成する必要はなく、要素を追加するだけで済みます。

var mySlice []*UselessStruct
for i := 0; i < 5; i++ {
    mySlice = append(mySlice, &UselessStruct{})
}

これは、事前割り当てなしで前の例と同じことを行いますが、サイズがわかっている場合は、次のようなものを使用します。

mySlice := make([]*UselessStruct, 0, 5)
for i := range mySlice {
    mySlice[i] = &UselessStruct{}
}

これにより、再割り当てが回避される場合があります。

于 2016-03-31T14:59:09.797 に答える