【问题标题】:initializing a struct containing a slice of structs in golang在 golang 中初始化一个包含结构切片的结构
【发布时间】:2017-07-23 16:46:30
【问题描述】:

我有一个结构,我想用 golang 中的一个结构切片进行初始化,但我想知道是否有更有效的版本将每个新生成的结构附加到切片:

package main

import (
    "fmt"
    "math/rand"
)

type LuckyNumber struct {
    number int
}

type Person struct {
    lucky_numbers []LuckyNumber
}

func main() {
    count_of_lucky_nums := 10
    // START OF SECTION I WANT TO OPTIMIZE
    var tmp []LuckyNumber
    for i := 0; i < count_of_lucky_nums; i++ {
        tmp = append(tmp, LuckyNumber{rand.Intn(100)})
    }
    a := Person{tmp}
    // END OF SECTION I WANT TO OPTIMIZE
    fmt.Println(a)
}

【问题讨论】:

标签: go struct slice


【解决方案1】:

您可以使用make() 以“全尺寸”分配切片,然后使用for range 对其进行迭代并填充数字:

tmp := make([]LuckyNumber, 10)
for i := range tmp {
    tmp[i].number = rand.Intn(100)
}
a := Person{tmp}
fmt.Println(a)

Go Playground 上试试。

请注意,在for 内部,我没有创建LuckyNumber 结构的新“实例”,因为切片已经包含它们;因为切片不是指针切片。所以在for循环中,我们只需要使用index expressiontmp[i]指定的结构体值即可。

【讨论】:

    【解决方案2】:

    make()可以按照icza建议的方式使用,也可以这样使用:

    tmp := make([]LuckyNumber, 0, countOfLuckyNums)
    for i := 0; i < countOfLuckyNums; i++ {
        tmp = append(tmp, LuckyNumber{rand.Intn(100)})
    }
    a := Person{tmp}
    fmt.Println(a)
    

    这样,您不必多次为tmp 分配内存:您只需在调用make 时执行一次。但是,与您调用make([]LuckyNumber, countOfLuckyNums) 的版本相反,这里的tmp 仅包含初始化值,而不包含未初始化的零值。根据您的代码,它可能会有所不同。

    【讨论】:

    • 我认为您的答案也有效,但为什么另一个答案会多次为 tmp 分配内存?
    • 切片 tmp 最初是空的。当您第一次附加到它时,运行时会分配一个小的底层数组并将值放入其中。当您继续附加到切片时,一旦它达到分配的底层数组的容量,运行时必须分配一个新的更大的数组并将所有内容从第一个移到新的。它必须这样做几次以适应重复的附加(在这种情况下,4 个分配:play.golang.org/p/_ameESD2-o)。
    • 哦,另一个答案也避免了重复分配(Fabien 指的是您在 OP 中的版本)。然而,另一个答案在 make() 调用中将切片的长度设置为等于 countOfLuckyNums,而 Fabien 的版本分配了该大小的底层数组,但保持切片长度为 0。如果您中断出于某种原因提前附加序列。示例:play.golang.org/p/bIs1jmEhrp
    猜你喜欢
    • 2018-01-20
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2013-01-25
    • 1970-01-01
    • 2013-04-16
    • 1970-01-01
    相关资源
    最近更新 更多