【问题标题】:Initializing a struct with slice data使用切片数据初始化结构
【发布时间】:2015-08-14 09:11:46
【问题描述】:

Golang 有三个点运算符 (...),当与函数调用一起使用时,它将切片的每个元素作为自己的参数转储,但似乎类似的机制不能与结构初始化器一起使用。

有没有办法通过在初始化结构时不访问切片中的每个元素来减少代码混乱?

是否可以将一个值一个接一个地附加到已初始化的结构中,或者在 for 循环中访问某种索引?

(我想可以访问已初始化结构的直接内存位置 - 但我不想这样做)

以下内容不起作用:(语法错误)

type Stats struct {
    Total uint64

    ICMP uint64

    UDP uint64
    TCP uint64

    FTP  uint64
    HTTP uint64
    MAIL uint64
    P2P  uint64
}

func newStats(slice [][]byte) *Stats {
    var tmp [8]uint64
    var err error

    for i, val := range slice {
        tmp[i], err = strconv.ParseUint(string(val), 10, 32)
        if err != nil {
             // Handle error
        }
    }

    return &Stats{tmp...} // Syntax error
}

这也不行:(当然)

return &Stats{
    for{ <code> }
}

这行得通,但我希望有一种惯用的、更快的方法,没有语法复制

return &Stats{
    tmp[0],
    tmp[1],
    tmp[2],
    tmp[3],
    tmp[4],
    tmp[5],
    tmp[6],
    tmp[7],
}

【问题讨论】:

  • 我认为这可能是一个不好的方法。如果字段的顺序发生变化怎么办?如果添加/删除字段怎么办?我建议始终使用显式形式(即T{A: s[0], B: s[1], /* ... */})。
  • 它可能是,这就是为什么它首先是不可能的。这让我很想知道。

标签: struct go initialization slice


【解决方案1】:

真正可以做到这一点的唯一方法是使用你提到的 unsafe 和 copy,但即使那样你也可能会遇到对齐问题。另一种“紧凑”的方式是在字段上使用reflect 和 for 循环,但这会很慢而且不是很惯用。

唯一可能的方法是引入您自己的语法并编写一个由go generate 调用的生成器脚本,它会将Struct{slice...} 自动转换为Struct{slice[0], slice[1] ... , slice[n] },其中n 是字段数,但是您必须自己动手。

【讨论】:

    【解决方案2】:

    除了 Jsor 的建议之外,您还可以创建一个 NewStats 方法,该方法采用椭圆参数并使用它来代替您的第一个示例。

    它也不是惯用的,但您可以减少代码中的混乱,并且只需要编写一次丑陋的部分......

    【讨论】:

    • 我正要提到这一点,但他的示例已经在 newStats 方法中,所以我认为它是多余的。
    猜你喜欢
    • 1970-01-01
    • 2018-01-20
    • 2021-02-19
    • 2017-07-23
    • 1970-01-01
    • 2011-04-03
    • 2010-09-22
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多