reflect.Value.MapIndex()返回的Value与reflect.ValueOf()返回的Value不同。

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

reflect.Value.MapIndex() returns a Value different from reflect.ValueOf()

问题

根据反射文档,reflect.Value.MapIndex()应该返回一个表示存储在特定键处的数据的reflect.Value。所以我的理解是以下两个表达式应该是相同的。在第一种情况下,我们从MapIndex()获取结果。在第二种情况下,我们从MapIndex()获取其底层数据,然后对其进行reflect.ValueOf()操作。

为什么需要额外的reflect.ValueOf()呢?

示例代码:

package main

import "fmt"
import "reflect"

func main() {
	test := map[string]interface{}{"First": "firstValue"}
	Pass(test)
}

func Pass(d interface{}) {
	mydata := reflect.ValueOf(d).MapIndex(reflect.ValueOf("First"))
	fmt.Printf("Value: %+v \n", mydata.Interface())
	fmt.Printf("Kind: %+v \n", mydata.Kind())
	fmt.Printf("Kind2: %+v \n", reflect.ValueOf(mydata.Interface()).Kind())
}

Go Play: http://play.golang.org/p/TG4SzrtTf0

英文:

According to the reflect documentation reflect.Value.MapIndex() should return a reflect.Value which represents the Value of the data stored at a specific key of a map. So my understanding would be that the following two expressions should be identical. In the first case we are getting the result from MapIndex(). In the second we are getting the result from MapIndex() getting it's underlying data and then doing a reflect.ValueOf() on that.

reflect.ValueOf(map).MapIndex("Key")
reflect.ValueOf(reflect.ValueOf(map).MapIndex("Key").Interface())

Why is the additional reflect.ValueOf() required?

Example Code:

package main

import "fmt"
import "reflect"

func main() {
	test := map[string]interface{}{"First": "firstValue"}
	Pass(test)
}

func Pass(d interface{}) {
	mydata := reflect.ValueOf(d).MapIndex(reflect.ValueOf("First"))
	fmt.Printf("Value: %+v \n", mydata.Interface())
	fmt.Printf("Kind: %+v \n", mydata.Kind())
	fmt.Printf("Kind2: %+v \n", reflect.ValueOf(mydata.Interface()).Kind())
}

Go Play: http://play.golang.org/p/TG4SzrtTf0

答案1

得分: 2

这是一个关于Go语言中接口的问题。在代码中,我明确声明了一个map[string]interface{},意味着每个键的位置上的值是一个interface{},而不是一个字符串,所以当我收到一个包含interface{}reflect.Value时,我不应该感到惊讶。

额外的reflect.ValueOf()函数深入一层,获取interface{}的底层值。我创建了两个例子,我相信这两个例子都证实了这种行为。

第一个例子使用了一个自定义的map[string]Stringer接口:http://play.golang.org/p/zXCn9Fce3Q

package main

import "fmt"
import "reflect"

type Test struct {
    Data string
}

func (t Test) GetData() string {
    return t.Data
}

type Stringer interface {
    GetData() string
}

func main() {
    test := map[string]Stringer{"First": Test{Data: "testing"}}
    Pass(test)
}

func Pass(d interface{}) {
    mydata := reflect.ValueOf(d).MapIndex(reflect.ValueOf("First"))
    fmt.Printf("Value: %+v \n", mydata.Interface())
    fmt.Printf("Kind: %+v \n", mydata.Kind())
    fmt.Printf("Kind2: %+v \n", reflect.ValueOf(mydata.Interface()).Kind())
}

返回结果:

Value: {Data:testing} 
Kind: interface 
Kind2: struct

第二个例子使用了一个map[string]string:http://play.golang.org/p/vXuPzmObgN

package main

import "fmt"
import "reflect"

func main() {
    test := map[string]string{"First": "firstValue"}
    Pass(test)
}

func Pass(d interface{}) {
    mydata := reflect.ValueOf(d).MapIndex(reflect.ValueOf("First"))
    fmt.Printf("Value: %+v \n", mydata.Interface())
    fmt.Printf("Kind: %+v \n", mydata.Kind())
    fmt.Printf("Kind2: %+v \n", reflect.ValueOf(mydata.Interface()).Kind())
}

返回结果:

Value: firstValue 
Kind: string 
Kind2: string
英文:

After thinking about this for a while this falls under the duh category. It has to do with the nature of interfaces in Go, which are reference objects which point to other things. I have explicitly declared my map to be map[string]interface{} meaning that the value at the location of each key is an interface{}, not a string, so I really shouldn't be surprised to receive a reflect.Value which holds an interface{}.

The additional reflect.ValueOf() dives one layer deeper to gain the underlying Value of the interface{}. I created two examples, both of which I believe confirm this behavior.

Example using a map[string]Stringer custom interface: http://play.golang.org/p/zXCn9Fce3Q

package main

import "fmt"
import "reflect"

type Test struct {
	Data string
}

func (t Test) GetData() string {
	return t.Data
}

type Stringer interface {
	GetData() string
}

func main() {
	test := map[string]Stringer{"First": Test{Data: "testing"}}
	Pass(test)
}

func Pass(d interface{}) {
	mydata := reflect.ValueOf(d).MapIndex(reflect.ValueOf("First"))
	fmt.Printf("Value: %+v \n", mydata.Interface())
	fmt.Printf("Kind: %+v \n", mydata.Kind())
	fmt.Printf("Kind2: %+v \n", reflect.ValueOf(mydata.Interface()).Kind())
}

returns

Value: {Data:testing} 
Kind: interface 
Kind2: struct

Example using a map[string]string: http://play.golang.org/p/vXuPzmObgN

package main

import "fmt"
import "reflect"

func main() {
	test := map[string]string{"First": "firstValue"}
	Pass(test)
}

func Pass(d interface{}) {
	mydata := reflect.ValueOf(d).MapIndex(reflect.ValueOf("First"))
	fmt.Printf("Value: %+v \n", mydata.Interface())
	fmt.Printf("Kind: %+v \n", mydata.Kind())
	fmt.Printf("Kind2: %+v \n", reflect.ValueOf(mydata.Interface()).Kind())
}

returns

Value: firstValue 
Kind: string 
Kind2: string 

答案2

得分: 1

func Pass(d interface{}) {
mydata := reflect.ValueOf(d).MapIndex(reflect.ValueOf("First"))
fmt.Printf("Value: %+v \n", mydata.Interface())
fmt.Printf("Kind: %+v \n", mydata.Kind())

At this point in your program, mydata is an interface, so no surprises that Go reports it as such when Kind() is called.

fmt.Printf("Kind2: %+v \n", reflect.ValueOf(mydata.Interface()).Kind())

Break this down:

s := mydata.Interface()  // s is a string
v := reflect.ValueOf(s)  // v is a reflect.Value
k := v.Kind()            // k is a reflect.Kind "string"

I think you may be being tripped up by the fact that your map contains interfaces, not strings.

英文:
func Pass(d interface{}) {
    mydata := reflect.ValueOf(d).MapIndex(reflect.ValueOf("First"))
    fmt.Printf("Value: %+v \n", mydata.Interface())
    fmt.Printf("Kind: %+v \n", mydata.Kind())

At this point in your program, mydata is an interface, so no surprises that Go reports it as such when Kind() is called.

    fmt.Printf("Kind2: %+v \n", reflect.ValueOf(mydata.Interface()).Kind())

Break this down:

s := mydata.Interface()  // s is a string
v := reflect.ValueOf(s)  // v is a reflect.Value
k := v.Kind()            // k is a reflect.Kind "string"

I think you may be being tripped up by the fact that your map contains interfaces, not strings.

huangapple
  • 本文由 发表于 2013年1月4日 00:10:53
  • 转载请务必保留本文链接:https://go.coder-hub.com/14142667.html
匿名

发表评论

匿名网友

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

确定