在函数内部访问结构体的指针值。

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

Access pointer value of a struct inside a function

问题

我想将一个结构体对象传递给一个函数,并能够从该函数中访问其指针值。我无法理解为什么以下代码会导致错误。

为了使其工作,我不得不将structType作为参数,如下所示:

func GetStructFieldPointers(u interface{}, structType reflect.Type, jsonFields []string) []interface{} {
    structVal := reflect.ValueOf(u).Elem()
    // structType := reflect.TypeOf(u)
    numberOfFields := structVal.NumField()
    numberOfJSONFields := len(jsonFields)
    res := make([]interface{}, numberOfJSONFields)
    fmt.Println(jsonFields)
    for fieldIndex, field := range jsonFields {
        for i := 0; i < numberOfFields; i++ {
            if structType.Field(i).Tag.Get("json") == field {
                valueField := structVal.Field(i)
                res[fieldIndex] = valueField.Addr().Interface()
            }
        }
    }

    return res
}

user := User{}
res := GetStructFieldPointers(&user, reflect.TypeOf(user), []string{"id", "name"})

我想知道如何将User{}作为参数,并在reflect.ValueOfreflect.TypeOf调用中使用。

英文:

I want to pass a struct object to a function & be able to access its pointer value from that function. I am not able to understand why the following is resulting in error.

func GetStructFieldPointers(u interface{}, jsonFields []string) []interface{} {
	structVal := reflect.ValueOf(&amp;u).Elem()
    structType := reflect.TypeOf(u)
	numberOfFields := structVal.NumField() // getting error here reflect:
                                           // call of reflect.Value.NumField
                                           // on interface Value
	numberOfJSONFields := len(jsonFields)
	res := make([]interface{}, numberOfJSONFields)
	fmt.Println(jsonFields)
	for fieldIndex, field := range jsonFields {
		for i := 0; i &lt; numberOfFields; i++ {
			if structType.Field(i).Tag.Get(&quot;json&quot;) == field {
				valueField := structVal.Field(i)
				res[fieldIndex] = valueField.Addr().Interface()
			}
		}
	}

	return res
}

type User struct {
	Id             int		`json:&quot;id&quot;`
	Name           string	`json:&quot;name&quot;`
	Address        string   `json:&quot;address&quot;`
}
user := User{}
res := GetStructFieldPointers(user, []string{&quot;id&quot;, &quot;name&quot;}) 

To make this work, I had to make structType as a parameter like following:

func GetStructFieldPointers(u interface{}, structType reflect.Type, jsonFields []string) []interface{} {
	structVal := reflect.ValueOf(u).Elem()
    // structType := reflect.TypeOf(u)
	numberOfFields := structVal.NumField() 
	numberOfJSONFields := len(jsonFields)
	res := make([]interface{}, numberOfJSONFields)
	fmt.Println(jsonFields)
	for fieldIndex, field := range jsonFields {
		for i := 0; i &lt; numberOfFields; i++ {
			if structType.Field(i).Tag.Get(&quot;json&quot;) == field {
				valueField := structVal.Field(i)
				res[fieldIndex] = valueField.Addr().Interface()
			}
		}
	}

	return res
}

user := User{}
res := GetStructFieldPointers(&amp;user, reflect.TypeOf(user), []string{&quot;id&quot;, &quot;name&quot;}) 

I like to know how to pass User{} as a parameter & use in both reflect.ValueOf & reflect.TypeOf calls.

答案1

得分: 3

在这行代码 structVal := reflect.ValueOf(&amp;u).Elem() 中,你获取的是一个接口的地址(你的函数的参数),而不是接口底层值的地址,然后你将指针传递给了 ValueOf,所以 .Elem() 调用返回的是指针指向的 "elem value",也就是接口,而不是结构体。

如果你确定传入的值是结构体而不是指针,你只需要这样写:structVal := reflect.ValueOf(u)

如果你的函数传入的是指针,例如 GetStructFieldPointers(&amp;u, ...,那么你需要这样写:structVal := reflect.ValueOf(u).Elem()

但是你也可以通过检查值的类型来处理这两种情况。

rv := reflect.ValueOf(u)
if rv.Kind() == reflect.Ptr {
    rv = rv.Elem()
}
if rv.Kind() == reflect.Struct {
    fmt.Println(rv.NumField())
}

更新
我仔细看了你的代码... 如果你想要获取结构体字段的地址,你需要将结构体的指针作为参数传递,否则这些字段将无法获取地址。

链接:https://play.golang.org/p/RaA2rau3s-

英文:

On this line: structVal := reflect.ValueOf(&amp;u).Elem() you're taking the address of an interface (the argument of your func) and not an address to the interface's underlying value, and then you're passing the pointer to ValueOf, so the .Elem() call returns the "elem value" to which the pointer points to, which is the interface, not struct.

If you know for a fact that the passed in value is a struct and not a pointer, all you need is this: structVal := reflect.ValueOf(u).

If a pointer was passed to your func, eg GetStructFieldPointers(&amp;u, ... then this is what you want: structVal := reflect.ValueOf(u).Elem().

But also you can handle both cases by checking the value's kind.

rv := reflect.ValueOf(u)
if rv.Kind() == reflect.Ptr {
	rv = rv.Elem()
}
if rv.Kind() == reflect.Struct {
	fmt.Println(rv.NumField())
}

https://play.golang.org/p/9F9LNnwEaH

Update:
Took a better look at your code... If you want to be able to get the addresses of your struct's fields, you need to pass a pointer to the struct as the argument, or else those fields are going to be unaddressable.

https://play.golang.org/p/RaA2rau3s-

huangapple
  • 本文由 发表于 2017年4月14日 15:09:51
  • 转载请务必保留本文链接:https://go.coder-hub.com/43406888.html
匿名

发表评论

匿名网友

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

确定