我有一个接口并返回接口的函数。它希望将结果初始化为源的副本,然后进行一些更改,并返回结果。例如:
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)
}
这样可行,但CopySomething()
方法似乎没必要(我需要为每个需要复制内容的接口使用另一种相同的方法)。有没有更好的方法在没有额外方法的情况下在original
内复制Updated()
?是否有一些更惯用的方法来实现这一目标?
在我正在处理的特定情况下,我可以通过实例化与original
相同类型的新实例来逃避(我真的不需要副本)。问题是否更简单?
根据Evan的评论,我想我还会尝试一些其他基于反思的事情:
newThing := reflect.New(reflect.TypeOf(original))
==> 编译错误:类型reflect.Value没有字段或方法SetX
newThing := reflect.New(reflect.TypeOf(original)).Interface().(Something)
===> 运行时错误:界面转换:** main.RealThing不是main.Something
newThing := reflect.Indirect(reflect.New(reflect.TypeOf(original))).Interface().(Something)
===> 运行时错误:无效的内存地址或无指针取消引用
在这一点上,我觉得我的反思变得愚蠢而且停止了只是打击它。
答案 0 :(得分:3)
由于您只需要实例化一个新实例,您可以使用反射来获取存储在接口中的对象的类型,并以这种方式实例化副本。像reflect.New(reflect.TypeOf(x))
之类的东西虽然您可能需要使用reflect.Indirect()
来分配新值而不是新指针。
这里记录了所有内容:http://golang.org/pkg/reflect/
一个可运行的版本:http://play.golang.org/p/z8VPzDKrSk
答案 1 :(得分:1)
newThing:= reflect.New(reflect.TypeOf(original))
==>编译错误:类型reflect.Value没有字段或方法SetX
如果original是指针则需要get元素:
elem := reflect.TypeOf(original).Elem()
newThing := reflect.New(elem)
newThing:= reflect.New(reflect.TypeOf(原始))。接口()。(东西)
===>运行时错误:界面转换:** main.RealThing不是main.Something
修复并继续...... 知道newThing是新的RealThing元素的指针,然后通过.Interface()获取此指针,但是在接口{}上。
elem := reflect.TypeOf(original).Elem()
newThingValue := reflect.New(elem)
newThingInterf := newThingValue.Interface()
对于获取指针直接指向RealThing需要做断言,然后
newThing := newThingInterface.(*RealThing)
所以你可以正常更新newThing
newThing.SetX(newX)//update new instance