【发布时间】:2021-05-27 12:24:46
【问题描述】:
假设我有这个实现Setter 接口的A 结构:
type Setter interface {
Set(key string, value string)
}
type A struct {
m map[string]string
}
func (a *A) Set(key string, value string) {
a.m[key] = value
}
我有一个不同的结构,其中包含Setter 接口的一些实现
type Holder struct {
val Setter
}
h := Holder{
val: &A{ map[string]string{} },
}
我需要得到一份 h.val 结构的副本,其中保存了所有值。
我已经尝试了以下解决方案,但它不起作用,导致panic: assignment to entry in nil map
(我们在初始化h时已经定义了映射,所以运行h.val.Set(k, v)不会出错)
l := reflect.New(
reflect.ValueOf(h.val).Elem().Type(),
).Interface().(Setter)
l.Set("A", "B")
如何创建一个结构的副本而不知道它包含哪些字段,只知道它实现的接口并将其值保存在变量中?
附言将Clone 方法添加到Setter 接口不是首选解决方案
【问题讨论】:
-
reflect.New,和内置的new一样只初始化根类型。也就是说,如果你给它A,你会得到初始化*A,但m字段将被初始化,它会被初始化为它的“零”值,在某些情况下是可以的,但在这种情况下地图是nil,因此出现了恐慌。做深拷贝是一回事,做“深”初始化虽然相似,但又是另一回事。在这两种情况下,您都必须使用reflect来遍历从根到叶的结构,并分别复制/初始化每个结构。祝你好运。