go中的reflect.ValueOf()和Value.Elem()有什么区别?
我几天前开始学习golang,发现reflect.Valueof()和Value.Elem()非常令人困惑。这两种功能/方法有什么区别,以及如何正确使用它们?
这两个函数/方法都返回一个值,并根据go doc
ValueOf返回一个新的Value,初始化为存储在接口i中的具体值。ValueOf(nil)返回零值。
Elem返回接口v包含的值或指针v指向的值。如果v的种类不是Interface或Ptr,它会感到恐慌。如果v为零,它将返回零值。
我从帖子中找到了此代码,但仍然不知道何时使用.Elem()
func SetField(obj interface{}, name string, value interface{}) error { // won't work if I remove .Elem()
structValue := reflect.ValueOf(obj).Elem()
structFieldValue := structValue.FieldByName(name)
if !structFieldValue.IsValid() {
return fmt.Errorf("No such field: %s in obj", name)
}
if !structFieldValue.CanSet() {
return fmt.Errorf("Cannot set %s field value", name)
}
structFieldType := structFieldValue.Type()
// won't work either if I add .Elem() to the end
val := reflect.ValueOf(value)
if structFieldType != val.Type() {
return fmt.Errorf("Provided value %v type %v didn't match obj field type %v",val,val.Type(),structFieldType)
}
structFieldValue.Set(val)
return nil
}
回答:
reflect.ValueOf()
是一个 函数
,请将其视为反射的切入点。当您具有“非反射”值(例如string
或)时int
,可以reflect.ValueOf()
用来获取其reflect.Value
描述符。
Value.Elem()
是一个 方法
的reflect.Value
。因此,只有在您已有时,才可以使用它reflect.Value
。您可以Value.Elem()
用来获取reflect.Value
由原始包装的值所指向的值()reflect.Value
。请注意,您也可以使用reflect.Indirect()
它。还有一个“用例”
Value.Elem()
,但是它更“高级”,我们在答案的最后返回。
要“离开”反射,可以使用常规Value.Interface()
方法,该方法将包装的值作为返回interface{}
。
例如:
var i int = 3var p *int = &i
fmt.Println(p, i)
v := reflect.ValueOf(p)
fmt.Println(v.Interface()) // This is the p pointer
v2 := v.Elem()
fmt.Println(v2.Interface()) // This is i's value: 3
这将输出(在Go Playground上尝试):
0x414020 30x414020
3
有关Go反射的重要介绍,请阅读The Go Blog:反射法则。尽管如果您只是从Go开始,我会专注于其他事情,并为以后的冒险留神。
回答:
这是一个高级主题,所以如果您不了解它,请不要惊慌。 不用了
我们看到了Value.Elem()
当指针包装在时如何用于“导航” reflect.Value
。的医生Value.Elem()
说:
Elem返回接口v包含的值或指针v指向的值。
因此,如果reflect.Value
包装一个接口值,Value.Elem()
也可以用来获取包装在该接口值中的具体值。
Go中的接口是它自己的主题,对于内部结构而言,您可以阅读Russ
Cox的Go数据结构:接口。再次重申,不一定是Go入门者的主题。
基本上,无论您传递给什么值reflect.ValueOf()
,如果它还不是接口值,它将被interface{}
隐式包装。如果传递的值已经是接口值,则存储在其中的具体值将作为传递interface{}
。如果您将指针传递给接口,则会出现第二个“用例”(否则,在Go!中非常罕见)。
因此,如果将指针传递给接口,则该指针将包装在一个interface{}
值中。您可以使用Value.Elem()
来获得目标值,该目标值将是接口值(而不是具体值),Value.Elem()
再次 使用它可以得到具体值。
这个例子说明了这一点:
var r io.Reader = os.Stdin // os.Stdin is of type *os.File which implements io.Readerv := reflect.ValueOf(r) // r is interface wrapping *os.File value
fmt.Println(v.Type()) // *os.File
v2 := reflect.ValueOf(&r) // pointer passed, will be wrapped in interface{}
fmt.Println(v2.Type()) // *io.Reader
fmt.Println(v2.Elem().Type()) // navigate to pointed: io.Reader (interface type)
fmt.Println(v2.Elem().Elem().Type()) // 2nd Elem(): get concrete value in interface: *os.File
在Go Playground上尝试一下。
以上是 go中的reflect.ValueOf()和Value.Elem()有什么区别? 的全部内容, 来源链接: utcz.com/qa/435958.html