web-dev-qa-db-ja.com

慣用的な方法でポインタのスライスを事前に割り当てて埋める方法は?

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}]

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

18
Dante

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

_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]
_

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

28

これを行うには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つのエントリに十分なスペースを事前に割り当てます。

8
jimt

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

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

また、スライスは参照型であるため、これらの5つのUselessStructsへの5つのポインターが事実上あります。

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

myStruct := &mySlice[0]

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

3
Jeremy Wall

完了するだけです。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{}
}

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

0
Marwan Burelle