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.
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
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
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With