如何创建一个结构体的副本,只包含它实现的接口和其值。

huangapple go评论139阅读模式
英文:

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
}

huangapple
  • 本文由 发表于 2021年5月27日 20:24:46
  • 转载请务必保留本文链接:https://go.coder-hub.com/67722069.html
匿名

发表评论

匿名网友

:?: :razz: :sad: :evil: :!: :smile: :oops: :grin: :eek: :shock: :???: :cool: :lol: :mad: :twisted: :roll: :wink: :idea: :arrow: :neutral: :cry: :mrgreen:

确定