How can I make the following work and make the output "Result is: [Value from GetFromMemory]."
?
Unfortunately I cannot change the method signatures of GetItem
and Get
.
http://play.golang.org/p/R5me3Q3y4W
package main
import "fmt"
type Key string
type Item struct {
Key Key
Value string
}
func GetItem(key Key) interface{} {
return &Item{key, "Value from GetFromMemory"}
}
// How can I make item point to the one created in GetItem?
func Get(key Key, item interface{}) {
item = GetItem(key)
}
func main() {
var item Item
Get("Key1", &item)
// This should print "Result is: [Value from GetFromMemory]."
fmt.Printf("Result is: [%s].", item.Value)
}
As you're dealing with interface{}
values you either need type assertions or reflection.
If you know which types you will deal with, type assertions are probably the way to go (Code on play):
func GetItem(key Key) interface{} {
return &Item{key, "Value from GetFromMemory"}
}
func Get(key Key, item interface{}) {
switch v := item.(type) {
case **Item:
*v = GetItem(key).(*Item)
}
}
// Usage:
var item *Item
Get("Key1", &item)
The code in Get
is laid out so that you can easily add more conditions for several more types. The type switch checks the underlying type of item
. In this case it is a pointer to a pointer to an Item
(it was *Item
in main, then we gave Get
the address of &item
, making it a **Item
).
In the section that matches when the type matches, we can then call GetItem
, assert that the resulted object is of type *Item
and copy it to *v
.
Note that I changed the item
variable to *Item
as you're producing a pointer value in GetItem
, so it makes more sense to get the pointer instead of a copy of an Item
object.
Also note that you need to check the result of type assertions like the one used to retrieve the value from GetItem
. If you don't and the type does not match, say, *Item
, your code will blow up with a runtime panic.
Checked type assertions:
v, ok := someInterfaceValue.(SomeType)
// ok will be true if the assertion succeeded
For the sake of completeness, you can solve your problem with reflection as well. Define Get
as follows (Example on play):
func Get(key Key, item interface{}) {
itemp := reflect.ValueOf(item).Elem()
itemp.Set(reflect.ValueOf(GetItem(key)))
}
What happens is that at first the reflected value of item
(type **Item
) is dereferenced, assuming that it is a pointer value, giving us a reflected value with type *Item
. Said value is then set with the reflected value of GetItem
by using the Set
method.
Of course you will need to check whether the kind of item
is actually a pointer. Not doing this and passing a non-pointer value to Get
will result in panics.