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 个无用结构预分配内存,存储为指针。如果我声明一个结构值 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 指针。如果你附加一个指针,它现在的长度为 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]

我的两个示例都将按您的预期工作,但出于纯粹的风格原因,我推荐第一个示例。

于 2013-06-04T00:01:51.187 回答
9

有两种方法可以做到这一点。一种是像您一样预先分配插槽。但是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 个条目预分配足够的空间。

于 2013-06-03T23:27:34.967 回答
3

你确定你需要指针吗?您的结构的值为零,因此:

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

由于切片是引用类型,因此您实际上有 5 个指向这 5 个 UselessStructs 的指针。

如果您需要获取对单个结构的引用以传递,那么您可以这样做

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 回答