How get pointer of struct's member from interface{}

huangapple go评论89阅读模式
英文:

How get pointer of struct's member from interface{}

问题

我想将结构体的指针传递给期望接口{}的函数,然后通过反射获取结构体成员的指针,并使用该指针进行修改。我已经阅读了很多问答并尝试了很多变化,但仍然无法使其工作。

让我们考虑下面的示例:

type Robot struct {
    Id int
}
f := func(i interface{}) {
    v := reflect.ValueOf(i).Elem().FieldByName("Id")
    ptr := v.Addr().Pointer()
    *ptr = 100
    //^ 这对于期望指针的函数是必需的:Scan(&pointerToValue)
}

robot := &Robot{}
f(robot)
println(robot.Id) //我希望在这里得到100

我认为问题在于对反射包的**Addr()Pointer()**方法的理解不够清楚。

英文:

I want to pass struct's pointer to function that expect interface{}. Then get (through reflection) the pointer to the struct's member and then modify it using this pointer. I've read a much of Q&A and tried much of variations, but still I can get it work.

Let's consider example below:

type Robot struct {
	Id int
}
f := func(i interface {}) {
	v :=  reflect.ValueOf(i).Elem().FieldByName("Id")
	ptr := v.Addr().Pointer()
	*ptr = 100
	//^ it needs to me for functions expecting the pointer: Scan(&pointerToValue)
}

robot := &Robot{}
f(robot)
println(robot.Id) //I want to get here 100

I think the problem in poor understanding what actually do Addr() and Pointer() methods of reflect package..

答案1

得分: 21

这是函数f的一个可工作版本:

func f(i interface{}) {
	v := reflect.ValueOf(i).Elem().FieldByName("Id")
	ptr := v.Addr().Interface().(*int)
	*ptr = 100
}

playground示例

将整数转换为指针的过程如下:

  • v 是表示int字段的reflect.Value
  • v.Addr() 是表示int字段的指针的reflect.Value
  • v.Addr().Interface() 是包含int指针的interface{}
  • v.Addr().Interface().(*int) 类型断言interface{}断言为*int

你可以直接设置字段而不获取指针:

func f(i interface{}) {
	v := reflect.ValueOf(i).Elem().FieldByName("Id")
	v.SetInt(100)
}

playground示例

如果你将值传递给期望interface{}的某些东西(比如db/sql的Scan方法),那么你可以去除类型断言:

func f(i interface{}) {
	v := reflect.ValueOf(i).Elem().FieldByName("Id")
	scan(v.Addr().Interface())
}

playground示例

英文:

Here's a working version of function f:

func f(i interface{}) {
  v := reflect.ValueOf(i).Elem().FieldByName("Id")
  ptr := v.Addr().Interface().(*int)
  *ptr = 100
}

playground example

The conversion to integer pointer goes as follows:

  • v is a reflect.Value representing the int field.
  • v.Addr() is a relfect.Value representing a pointer to the int field.
  • v.Addr().Interface() is an interface{} containing the int pointer.
  • v.Addr().Interface().(*int) type asserts the interface{} to a *int

You can set the field directly without getting a pointer:

func f(i interface{}) {
  v := reflect.ValueOf(i).Elem().FieldByName("Id")
  v.SetInt(100)
}

playground example

If you are passing the value along to something expecting interface{} (like the db/sql Scan methods), then you can remove the type assertion:

func f(i interface{}) {
  v := reflect.ValueOf(i).Elem().FieldByName("Id")
  scan(v.Addr().Interface())
}

playground example

huangapple
  • 本文由 发表于 2015年1月17日 05:12:29
  • 转载请务必保留本文链接:https://go.coder-hub.com/27992821.html
匿名

发表评论

匿名网友

:?: :razz: :sad: :evil: :!: :smile: :oops: :grin: :eek: :shock: :???: :cool: :lol: :mad: :twisted: :roll: :wink: :idea: :arrow: :neutral: :cry: :mrgreen:

确定