当前位置: 首页 > 面试题库 >

Golang反射:无法设置包装结构的界面字段

赵征
2023-03-14
问题内容

我正在尝试实现一种方法,该方法更改可以具有任意结构的对象中字段的值。当我有一个指向结构的指针时,字段的遍历是没有问题的。但是,当我有一个不包装指向结构的指针但包装结构本身的接口时,简而言之,我无法更改字段:

// The following doesn't work
var x interface{} = A{Str: "Hello"}
// This panics: reflect: call of reflect.Value.Field on ptr Value
reflect.ValueOf(&x).Field(0).SetString("Bye")
// This panics: reflect: call of reflect.Value.Field on interface Value
reflect.ValueOf(&x).Elem().Field(0).SetString("Bye")
// This panics: reflect: reflect.Value.SetString using unaddressable value
reflect.ValueOf(&x).Elem().Elem().Field(0).SetString("Bye")
// This prints `false`. But I want this to be settable
fmt.Println(reflect.ValueOf(&x).Elem().Elem().Field(0).CanSet())

// This works
var z interface{} = &A{Str: "Hello"}
// This prints `true`
fmt.Println(reflect.ValueOf(z).Elem().Field(0).CanSet())

长:http://play.golang.org/p/OsnCPvOx8F

我已阅读《反射定律》,因此我知道只有在具有指向结构的指针时,才可以修改字段。现在我的问题是: 如何获取结构数据的指针?

更新:

我基本上使用它来工作,y := reflect.New(reflect.TypeOf(x))因此y现在可以设置的值。有关广泛的示例,请参见:https
:
//gist.github.com/hvoecking/10772475


问题答案:

您似乎正在尝试修改存储在接口变量中的动态值。您可以对接口变量执行的唯一操作是获取或设置动态值(进行复制的操作),并检查存储值的类型。

要了解为什么事情是这样的,请想象有一个这样的操作,并且我们有以下代码:

var ptr *A = pointer_to_dynamic_value(x)
x = B{...}

什么是ptr现在代表什么?在将新值分配给接口变量时,该语言可以自由地重用存储,因此ptr可能现在指向该B值的内存,这破坏了该语言的类型安全性(使用当前的编译器,只能保证将其重用用于小值,但重点仍然存在)。

更改存储在接口中的值的唯一安全方法是将值复制出来,然后分配回修改后的版本。例如:

a := x.(A)
a.Str = "Bye"
x = a

reflect包装反映了这些限制,因此reflect.Value代表被视为只读动态值的字段。

您可以在第一个示例中设置字段,因为的动态值z*A指针而不是结构本身:这意味着可以修改引用的结构。



 类似资料:
  • 本文向大家介绍go语言通过反射获取和设置结构体字段值的方法,包括了go语言通过反射获取和设置结构体字段值的方法的使用技巧和注意事项,需要的朋友参考一下 本文实例讲述了go语言通过反射获取和设置结构体字段值的方法。分享给大家供大家参考。具体实现方法如下: 希望本文所述对大家的go语言程序设计有所帮助。

  • 问题内容: 来自文档 Elem返回接口v包含的值或指针v指向的值。 如果v的种类不是Interface或Ptr,它会感到恐慌。如果v为零,它将返回零值。 间接返回v指向的值。 如果v是nil指针,则Indirect返回零值。如果v不是指针,则Indirect返回v。 那么我可以安全地假设以下情况吗? 间接方法仅仅是上述方法的一种便捷方法吗? 问题答案: 如果a 是指针,则等效于。如果不是指针,则它

  • 问题内容: 我无法使用Java反射将值设置为字段。字段数据类型为。但是,如果数据类型是基本类型,即I,我就可以设置该值。 这是带有类型和原始类型的简单VO : 这是我的java反射代码: 输出为: 我试图设定与价值,,等什么作品。 问题答案: 根据此,被调用以设置一个字段,该字段是用原语类型的值的参考布尔类型。在非反射等效项中,编译器会将原始类型’true’转换(或装箱)为引用类型,以便其类型检查

  • 问题内容: 我正在与一个非开源项目合作,我需要修改一个或多个其类。 在一个类中是以下集合: 我需要做的就是在这里使用反射和并发hashmap。我试过下面的代码,但是不起作用。 问题答案: 希望这是您要尝试做的事情: 它打印:

  • 问题内容: 我有这样的数据结构: 是另一个结构。 然后,当我尝试在Users切片中添加一些新值时,如下所示: 我不断收到此错误: 还尝试在这里https://github.com/golang/go/issues/3117变通方法,像这样: 但是没有运气,仍然是完全相同的错误。 并且还尝试使用指针声明地图,因此:,仍然没有运气。 问题答案: 首先,对于这个问题,本文中的解决方案为什么在将值设置为结

  • 问题内容: 该程序的输出是 map [] ,但我想要 map [Id:true name:true] 我试图弄干我的一些SQL CRUD代码,并认为嵌入处理读和写数据库的持久性结构会很好。在下面的示例中,持久性结构将为Inner,而我的模型将为Outer。谢谢! 问题答案: 你不能 您专门在上调用了一个方法,该方法不知道其嵌入位置。嵌入不是继承,它是简单的自动委派。 您可能希望将它们包装在一个通用