gpt4 book ai didi

reflection - Golang 反射.值行为

转载 作者:IT王子 更新时间:2023-10-29 02:34:46 25 4
gpt4 key购买 nike

我目前对 golang 反射包的行为感到绝望,对我来说这似乎根本不一致。

1) 据我了解,reflect.Value 似乎带有指向基础值的指针。例如。如果我打电话

var s string
v1 := reflect.ValueOf(&s).Elem()
v2 := v1
v2.SetString("Hello World!")
fmt.Println(s)

它打印出“Hello World!”。但是,这似乎不适用于通过调用 Field() 获得的 reflect.Value。

val := ... //Assign a reflect.Value to it
nextval := val.Field(0) //Make sure that Field exists and is of type map
nextval = reflect.MakeMap(reflect.MapOf(KEY, ELEM))
nextval.SetMapIndex(Some_value_of_type_KEY, Something_of_type_ELEM)
fmt.Println(nextval.MapKeys()
fmt.Println(val.Field(index).MapKeys())

这打印

[Some_value_of_type_KEY]
[]

这是一个主要的烦恼。有谁知道为什么会这样吗?

============================================= ====

2)考虑函数

func Test(v interface{}) {
val := reflect.ValueOf(v)
if val.Kind() != reflect.Struct {
fmt.Println("It is a struct")
}
}

如果我用任何结构作为参数调用它,它会打印“This is a struct”。但是,我将无法使用 val 为 v 中的内容分配新值,由于该值不可寻址。通过以下解决方法:

func Test(v interface{}) {
val := reflect.ValueOf(&v).Elem()
if val.Kind() != reflect.Struct {
fmt.Println("This never get's printed!")
}
}

根据文档,我会假设,通过使用 '&' 我使用指向 v 的指针并通过调用 Elem() 我得到它指向的元素,因此 val.Kind() 应该仍然返回同样的事情。它没有。 val.Kind() 现在是一个 reflect.Interface。

有没有办法不用走

valForTestingKind := reflect.ValueOf(v)
valForSettingNewValue := reflect.ValueOf(&v).Elem()

因为这在某种程度上感觉不对。

最佳答案

第 1 部分:

通过分配给 nextval,您将打破它与原始 val 的关联。相反,请使用 Set() 方法。

nextval.Set(reflect.MakeMap(reflect.MapOf(KEY, ELEM)))

Set() 相当于反射世界中的赋值。当然,您必须像在第一个代码示例中那样使用 reflect.ValueOf(&v).Elem() 确保它是可分配的。


第 2 部分:

这里的问题是您有另一个间接级别。 v 是 interface{} 类型,并且有一个具体值,其类型是 Kind 结构。就像每个接受接口(interface)类型参数的函数一样,当您调用 reflect.ValueOf 时,参数会自动转换为该类型。但是,将一个接口(interface)转换为另一个接口(interface)会导致在新接口(interface)类型中重新装箱具体值。重新装箱前的类型信息丢失。例如,接受 io.Writer 的函数不知道调用函数将其视为 io.ReaderWriter。

在此上下文中,这意味着 reflect.ValueOf 无法判断您传递的是 os.File(某个结构)还是封装在接口(interface){}中的文件。它假设您传递了一个 os.File 并向您展示了 Kind“struct”。

但是,当您将指针传递给 interface{} 时,您传递的是一个可以修改的 interface{} 变量。您没有传递底层的具体类型,这会产生重要的后果。您可以 .Set() 任何东西,而不仅仅是原始具体类型所允许的。您也无法编辑单个字段,因为界面中的任何内容都不可分配。{}如果具体类型实际上是一个指针,您可以执行第四次取消引用 (.Elem()) 并从那里修改字段。

那么,这在代码方面意味着什么?

//let v = an interface{} with a concrete type of SomeStruct
val := reflect.ValueOf(&v).Elem()
fmt.Println(val.Elem().Kind()) // struct
val.Elem().Field(0).Set(10) // PANIC! Field isn't assignable.
val.Set("a string which is not a SomeStruct")
fmt.Println(val.Elem().Kind()) // string

我在这里做了一个例子:http://play.golang.org/p/6MULn3KoNh

关于reflection - Golang 反射.值行为,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/17385994/

25 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com