首先,我要强调的是,此解决方案的实际生产代码答案是 @izca 的,在您进一步深入兔子洞之前,我将在这里报告:
m := MyStruct{A: arr[0], B: arr[1], C: arr[2], D: arr[3], E: arr[4]}
但是必须有其他方法可以做到这一点。如果你是 C 程序员,你就会知道,如果你有一个大小相同的结构体和数组,它们是可以被强制转换的,对吧?
就是这样,使用 unsafe 包进行 C 风格类型转换(Go 中的转换):
func main() {
arr := [5]int{1, 2, 3, 4, 5}
q := (*MyStruct)(unsafe.Pointer(&arr))
fmt.Printf("%#v\n", q)
}
type MyStruct struct {
A int
B int
C int
D int
E int
}
Playground
你真的应该使用这个吗?不。我应该强调这是玩弄的东西,如果没有很好的理由,你不应该真的这样做。包unsafe,从它的名字可以很清楚地推断出来,是不安全的。它不提供任何保证,并且如果使用不当,可能会破坏从垃圾收集器到 cgo 到交叉编译的任何东西。然而,理所当然地认为结构的内存表示保持一致(我强调,这不是由spec定义的,因此依赖于实现),这个解决方案将继续工作。
这里要注意的一件有趣的事情是*q 和arr 都指向内存中的同一个东西。这意味着你可以做这样有趣的事情:
arr := [5]int{1, 2, 3, 4, 5}
q := (*MyStruct)(unsafe.Pointer(&arr))
fmt.Printf("%#v\n", q) // => &main.MyStruct{A:1, B:2, C:3, D:4, E:5}
arr[0] = 0xFFFF
fmt.Printf("%#v\n", q) // => &main.MyStruct{A:65535, B:2, C:3, D:4, E:5}
当然,除了是一个有趣的实验之外,这也意味着通常将引用保留在真实代码中是一个坏主意。所以如果你必须使用不安全的解决方案,你应该按值复制,这样你就知道它不会引用原始数组。
// with the extra asterisk, called indirect,
// q will be type MyStruct and the example above will fail
q := *(*MyStruct)(unsafe.Pointer(&arr))
最后,一个更现实的解决方案,但无效,除非您有一个包含许多字段的结构(在这种情况下,您可能应该只使用代码生成,为什么要使用这么大的结构?)
arr := [5]int{1, 2, 3, 4, 5}
v := reflect.ValueOf(&MyStruct{}).Elem()
for i, val := range arr {
v.Field(i).SetInt(int64(val))
}
fmt.Printf("%#v\n",v.Interface().(MyStruct))
Playground
你真的应该使用这个吗?不是真的 - 但它比使用 unsafe 更好,因为 reflect 库保留了 Go 1 compatibility promise。但是请注意,这将是所有解决方案中最慢的,尤其是当您添加了所有在现实生活中实际需要处理的检查时。如上所述,一般来说,如果您确实有那么多字段可以证明使用反射来缩小代码,您应该首先问自己拥有这么大的结构有什么好处,如果您对此有一个很好的答案,那么真正的解决方案是构建一个代码生成器,将数组复制到结构中。
(这个答案的重点是表明是的,确实,有一些方法可以真正解决 OP 的问题 - 但也有非常正当的理由不应该使用它们!)