英文:
How to create a copy of a struct only having interface it implements and it's value
问题
假设我有一个实现了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时定义了map,所以运行h.val.Set(k, v)不会出错)
l := reflect.New(
    reflect.ValueOf(h.val).Elem().Type(),
).Interface().(Setter)
l.Set("A", "B")
在不知道结构体包含哪些字段的情况下,我该如何创建一个结构体的副本,只知道它实现了哪个接口,并且将其值存储在一个变量中?
附注:向Setter接口添加Clone方法不是首选解决方案
英文:
Let's say I have this A struct that implements Setter interface:
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
}
And I have one different struct that holds some implementation of Setter interface
type Holder struct {
    val Setter
}
h := Holder{
    val: &A{ map[string]string{} },
}
What i need is to get a copy of the h.val struct with all values saved.
I have already tried the following solution but it did not work, resulting with panic: assignment to entry in nil map
(We have defined the map when initiallizing h, so by running h.val.Set(k, v) we won't get any errors)
l := reflect.New(
    reflect.ValueOf(h.val).Elem().Type(),
).Interface().(Setter)
l.Set("A", "B")
How can I create a copy of a struct without knowing which fields it consists of, only knowing the interface it implements and having it's value in a variable?
p.s. Adding Clone method to Setter interface is not a preferred solution
答案1
得分: 1
在所有情况下,将Clone方法添加到Setter接口并不是首选解决方案,因为只有Setter的实现知道应该如何进行“克隆”,选择余地不多。
例如:克隆A结构体应该创建一个指向相同映射的新结构体吗?还是应该复制映射?
如果你的意图真的是要克隆,你可能想要第二种情况,但你会发现这很快就超出了简单的reflect操作的范围。
如果你的代码实际上只处理A结构体,你可以传递显式的A值。你可能仍然需要一个.Clone()方法或一个Clone(a *A)函数。
如果你的唯一问题是A的零值是无效的,你可以修复Set():
func (a *A) Set(key string, value string) {
    if a.m == nil {
        a.m = make(map[string]string)
    }
    a.m[key] = value
}
英文:
> Adding Clone method to Setter interface is not a preferred solution
in all generality, since only the Setter implementation knows how it should be "cloned", there isn't much choice.
For example : should "cloning" an A struct create a new struct pointing at the same mapping ? or should it duplicate the mapping ?
If your intention is really to clone, you probably want the second, but you can see it will quickly fall outside the scope of a simple reflect operation.
If your code actually only deals with A structs, you may pass explicit A values. You will probably still need a .Clone() method or a Clone(a *A) function.
If your only issue is that a zero value for A is invalid, you can fix Set() :
func (a *A) Set(key string, value string) {
    if a.m == nil {
        a.m = make(map[string]string)
    }
    a.m[key] = value
}
通过集体智慧和协作来改善编程学习和解决问题的方式。致力于成为全球开发者共同参与的知识库,让每个人都能够通过互相帮助和分享经验来进步。


评论