'getting reflect.Value(&foo) from reflect.Value(foo)

the title of the question pretty much sums it up. I'm playing with reflections using Go, and I'm trying to get the address of what reflect.Value() is pointing at.

why?

I have a function that can receive a struct in two ways: first.. this is the struct

type UserInfo struct {
    Name   string        `json:"name"`
    Roles  *[]model.Role `json:"role"`
    UserId int           `json:"user_id" db:"id"`
}

one:

var userInfo types.UserInfo
myFunc(&userInfo)

with this method i'm good since since it's a pointer to a struct that has it's memory allocated

the 2nd method:

var userInfo *types.UserInfo
myFunc(userInfo)

so here if I do reflect.Value() it's a Nil Pointer. i want to allocate that struct and to point userInfo to the new place. now I can easily do that if I paste &userInfo as well and perform:

myFunc(dst interface{}, dstAddr interface{})
{
 v := reflect.ValueOf(dstAddr)
 t := reflect.TypeOf(dst)
 ptr := reflect.New(t.Type())
 ...
 v.Elem().Set(ptr)
}

now I would except that reflect.ValueOf(dst).Addr() will be the same as reflect.ValueOf(&dst) but actually reflect.ValueOf(dst).CanAddr() returns false.

so.. is there a way to get reflect.ValueOf(&dst) while only having reflect.ValueOf(dst) ?



Solution 1:[1]

Whatever you pass to reflect.ValueOf() or any other function, a copy will be made.

That being said, reflect.Value(foo) cannot possibly give you back the address of the original foo, it could only give you back the address of the copy. To avoid further confusion, in this case Value.CanAddr() would return false, letting you know the address that could be returned using Value.Addr() would not be what most would expect, it wouldn't be a useful address.

As you indicated, you want to pass a single value, so pass &foo. Doing so you will be able to get the foo value pointed by &foo using Value.Elem().

Also note that the (wrapped) foo value you get by Value.Elem() will be addressable, since it was acquired from a reflect.Value wrapping &foo. So if the reflect.Value is not reflect.ValueOf(foo) but reflect.ValueOf(&foo).Elem(), you are able to get back (to) &foo.

See this example:

func main() {
    var foo = 3

    fmt.Println("Address:", &foo)
    bar(&foo)
    fmt.Println("After:", foo)
}

func bar(x interface{}) {
    v := reflect.ValueOf(x)

    v2 := v.Elem()
    fmt.Println("Passed pointed value:", v2.Interface())
    v2.Set(reflect.ValueOf(4))

    fmt.Println("Address got from pointed value:", v2.Addr())
}

This will output (try it on the Go Playground):

Address: 0xc000080010
Passed pointed value: 3
Address got from pointed value: 0xc000080010
After: 4

Sources

This article follows the attribution requirements of Stack Overflow and is licensed under CC BY-SA 3.0.

Source: Stack Overflow

Solution Source
Solution 1