从reflect.Value(foo)获取reflect.Value(&foo)

时间:2020-10-06 06:21:39

标签: go pointers reflection

问题的标题几乎总结了一下。我正在使用Go进行反射,并且试图获取reflect.Value()指向的地址。

为什么?

我有一个可以通过两种方式接收结构的函数: 首先..这是结构

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

一个:

var userInfo types.UserInfo
myFunc(&userInfo)

使用这种方法我很好,因为它是指向已分配内存的结构的指针

第二种方法:

var userInfo *types.UserInfo
myFunc(userInfo)

因此,如果我这样做reflect.Value(),则为零指针。 我想分配该结构并将userInfo指向新的地方。 现在,如果我也粘贴&userInfo,我可以轻松地做到这一点 并执行:

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

现在,除了reflect.ValueOf(dst).Addr()reflect.ValueOf(&dst)相同外,实际上reflect.ValueOf(dst).CanAddr()返回false。

所以..有一种方法可以只拥有reflect.ValueOf(&dst)而获得reflect.ValueOf(dst)吗?

1 个答案:

答案 0 :(得分:2)

无论您传递给reflect.ValueOf()或任何其他函数,都将进行复制。

话虽这么说,reflect.Value(foo)可能无法将原始foo的地址退还给您,而只能将您的副本地址退还给您。为避免进一步的混乱,在这种情况下,Value.CanAddr()将返回false,让您知道可以使用Value.Addr()返回 的地址并不是大多数人期望的,这不是一个有用的地址。

如前所述,您想传递一个单个值,因此传递&foo。这样做,您将能够使用Value.Elem()获得foo所指向的&foo值。

还要注意,foo所获得的(包装的)Value.Elem()值将是可寻址的,因为它是从reflect.Value包装&foo获得的。因此,如果reflect.Value不是(不是 reflect.ValueOf(foo),而是reflect.ValueOf(&foo).Elem(),则可以返回&foo

请参见以下示例:

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

这将输出(在Go Playground上尝试):

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