英文:
Copy or New instance of an interface
问题
我有一个函数,它接受一个接口并返回一个接口。我想要将结果初始化为源的副本,然后进行一些更改,并返回结果。例如:
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:
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
通过集体智慧和协作来改善编程学习和解决问题的方式。致力于成为全球开发者共同参与的知识库,让每个人都能够通过互相帮助和分享经验来进步。
评论