复制或新建接口的实例

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

Copy or New instance of an interface

问题

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

Playground

type Something interface {
    CopySomething() Something  // 我想要摆脱这个方法
    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()  // 我想要在没有.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()方法似乎是不必要的(而且我需要为每个需要复制的接口添加另一个相同的方法)。在Updated()函数内部,有没有更好的方法来复制original而不需要额外的方法?有没有更符合惯用法的方法来实现这个?

在我正在处理的具体情况中,我可以只实例化一个与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)

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

到这一点,我感觉我的反射变得有些愚蠢了,所以我停止了对它的乱打乱敲。

英文:

I have a function that takes an interface and returns an interface. It would like to initialize the result to a copy of the source, then make some changes, and return the result. For example:

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)
}

This works, but the CopySomething() method seems unnecessary (and I'd need another identical method for every interface that needs to copy things). Is there a better way to make a copy of original inside of Updated() without an extra method? Is there some more idiomatic way to achieve this?

In the specific case I'm working on, I could get away with just instantiating a new instance of the same type as original (I don't really need the copy). Is the problem any simpler that way?


Based on Evan's comment, I thought I'd give some of the other reflect-based things I've already tried:

newThing := reflect.New(reflect.TypeOf(original))

==>
Compile error: type reflect.Value has no field or method SetX

newThing := reflect.New(reflect.TypeOf(original)).Interface().(Something)

===>
Runtime error: interface conversion: **main.RealThing is not main.Something

newThing := reflect.Indirect(reflect.New(reflect.TypeOf(original))).Interface().(Something)

===>
Runtime error: invalid memory address or nil pointer dereference

At this point, I felt my reflect was becoming silly and stopped just whacking at it.

答案1

得分: 9

由于您只需要实例化一个新实例,您可以使用反射来获取接口中存储的对象的类型,并以此方式实例化一个副本。类似于reflect.New(reflect.TypeOf(x)),尽管您可能需要使用reflect.Indirect()来分配一个新值而不是一个新指针。

这里有详细的文档:http://golang.org/pkg/reflect/

还有一个可运行的版本:http://play.golang.org/p/z8VPzDKrSk

英文:

Since you just need to instantiate a new instance you can use reflection to get the type of the object stored in the interface and instantiate a copy that way. Something like reflect.New(reflect.TypeOf(x)) though you may have to play with reflect.Indirect() in order to allocate a new value and not a new pointer.

It's all documented here: http://golang.org/pkg/reflect/

And a runnable version: http://play.golang.org/p/z8VPzDKrSk

答案2

得分: 2

newThing := reflect.New(reflect.TypeOf(original))
// ==>
// newThing := reflect.TypeOf(original).Elem()
// newThing := reflect.New(newThing)

newThing := reflect.New(reflect.TypeOf(original)).Interface().(Something)
// ===>
// newThingValue := reflect.New(reflect.TypeOf(original).Elem())
// newThingInterf := newThingValue.Interface()
// newThing := newThingInterf.(*RealThing)

newThing.SetX(newX) // update new instance

你可以在https://play.golang.org/p/N-pwH5J_el中查看示例代码的运行结果。

英文:

> newThing := reflect.New(reflect.TypeOf(original))
> > ==> Compile error: type reflect.Value has no field or method SetX

If original is an pointer is need get element:

elem := reflect.TypeOf(original).Elem()    
newThing := reflect.New(elem)

> newThing :=
> reflect.New(reflect.TypeOf(original)).Interface().(Something)
> > ===> Runtime error: interface conversion: **main.RealThing is not main.Something

Fixing and continuing...
Knowing that newThing is pointer for an new RealThing element, then get this pointer by .Interface(), but on interface{}.

elem := reflect.TypeOf(original).Elem()    
newThingValue := reflect.New(elem)
newThingInterf := newThingValue.Interface()

For get pointer direct to RealThing is need do assertion, then

newThing := newThingInterface.(*RealThing)

So you can update newThing normally

newThing.SetX(newX)//update new instance

See working in https://play.golang.org/p/N-pwH5J_el

huangapple
  • 本文由 发表于 2014年4月9日 05:04:08
  • 转载请务必保留本文链接:https://go.coder-hub.com/22948133.html
匿名

发表评论

匿名网友

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

确定