复制或接口的新实例

时间:2014-04-08 21:04:09

标签: go

我有一个接口并返回接口的函数。它希望将结果初始化为源的副本,然后进行一些更改,并返回结果。例如:

Playground

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)

===> 运行时错误:无效的内存地址或无指针取消引用

在这一点上,我觉得我的反思变得愚蠢而且停止了只是打击它。

2 个答案:

答案 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

请参阅https://play.golang.org/p/N-pwH5J_el