我有一个函数,它接受一个接口并返回一个接口。它想将结果初始化为源的副本,然后进行一些更改,并返回结果。例如:
type Something interface {
CopySomething() Something // I'd like to get rid of this
SetX(x int)
}
type RealThing struct {
x int
}
func (t *RealThing) SetX(x int) {
t.x = x
}
func (t *RealThing) CopySomething() Something {
newT := *t
return &newT
}
func Updated(original Something, newX int) Something {
newThing := original.CopySomething() // I'd like to make the copy without .CopySomething()
newThing.SetX(newX)
return newThing
}
func main() {
a := &RealThing{x: 1}
b := Updated(a, 5)
fmt.Printf("a = %v\n", a)
fmt.Printf("b = %v\n", b)
}
Run Code Online (Sandbox Code Playgroud)
这有效,但该CopySomething()方法似乎没有必要(对于需要复制内容的每个接口,我都需要另一个相同的方法)。有没有更好的方法可以original在Updated()没有额外方法的情况下制作inside 的副本?有没有更惯用的方法来实现这一目标?
在我正在处理的特定情况下,我可以通过实例化与original(我真的不需要副本)相同类型的新实例而逃脱。这样问题会更简单吗?
根据埃文的评论,我想我会给出一些我已经尝试过的其他基于反射的东西:
newThing := reflect.New(reflect.TypeOf(original))
Run Code Online (Sandbox Code Playgroud)
==> 编译错误:类型reflect.Value 没有字段或方法SetX
newThing := reflect.New(reflect.TypeOf(original)).Interface().(Something)
Run Code Online (Sandbox Code Playgroud)
===> 运行时错误:接口转换:**main.RealThing 不是 main.Something
newThing := reflect.Indirect(reflect.New(reflect.TypeOf(original))).Interface().(Something)
Run Code Online (Sandbox Code Playgroud)
===> 运行时错误:无效的内存地址或零指针取消引用
在这一点上,我觉得我的反思变得愚蠢,不再只是敲打它。
由于您只需要实例化一个新实例,因此您可以使用反射来获取存储在接口中的对象的类型并以这种方式实例化一个副本。就像reflect.New(reflect.TypeOf(x))你可能不得不reflect.Indirect()为了分配一个新值而不是一个新指针而玩一样的东西。
全部记录在这里:http : //golang.org/pkg/reflect/
还有一个可运行的版本:http : //play.golang.org/p/z8VPzDKrSk