Go语言 如何以惯用的方式预分配和填充一片指针?

pinkon5k  于 2023-09-28  发布在  Go
关注(0)|答案(4)|浏览(138)

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预分配内存,存储为指针。如果我声明一个struct值的切片eq:

mySlice := make([]UselessStruct, 5)

然后这会创建5个空的结构体-- appending不会替换空的结构体,而是继续添加到切片中,所以这段代码的最终结果是:
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}]

预分配和填充切片的惯用方法是什么?

vmpqdwk3

vmpqdwk31#

对于你的第一个例子,我会这样做:

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

在这两个示例中,您所面临的问题是,您正在追加到一个长度已经正确的切片。如果你设置mySlice := make([]*UselessStruct, 5),你需要一个长度为5的nil指针片。如果附加一个指针,它现在的长度为6。
因此,您需要使用mySlice := make([]*UselessStruct, 0, 5)。这将创建一个长度为0但容量为5的切片。每次你追加它都会在长度上加一,但是它不会重新分配,直到你超过切片的容量。

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

我的两个例子都能像你期望的那样工作,但我推荐第一个纯粹是出于风格的原因。

pb3s4cty

pb3s4cty2#

有两种方法可以做到这一点。一种是像您所做的那样预先分配插槽。但是不使用append,您只需索引到现有的插槽之一:

mySlice[i] = &UselessStruct{}

第二种是使用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个条目预分配了足够的空间。

yr9zkbsy

yr9zkbsy3#

你确定你需要指点吗?你的struct有一个零值,所以:

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

由于切片是引用类型,因此您实际上有5个指向这5个UselessStruct的指针。
如果你需要得到一个引用到一个单独的结构来传递,那么你可以这样做

myStruct := &mySlice[0]

现在您有了一个指向UselessStruct的指针,可以根据需要使用它。它的代码比你拥有的要少得多,并且利用了Go的零值特性。

7y4bm7vi

7y4bm7vi4#

只是为了完成:append对nil slice起作用,所以你不需要用make来创建slice,你只需要向它追加元素就可以了。

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

这可以避免一些重新分配。

相关问题