无法设置类型为接口的结构的字段{}
Can't set field of a struct that is typed as an interface{}
我一直在为 reflect 包苦苦挣扎。下面的代码符合我的预期:
package main
import (
"reflect"
"log"
)
type Car struct {
Model string
}
type Person struct {
Name string
Cars []Car
}
func ModifyIt(parent interface{},fieldName string, val interface{}) {
slice := reflect.ValueOf(parent).Elem()
nth := slice.Index(0)
//row := nth.Interface() // this line causes errors
row := nth.Interface().(Person)
elem := reflect.ValueOf(&row).Elem()
field := elem.FieldByName(fieldName)
log.Println(field.CanSet())
}
func main() {
p := []Person{Person{Name:"john"}}
c := []Car{Car{"corolla"},Car{"jetta"}}
ModifyIt(&p,"Cars",&c)
}
但是,如果我将行 row := nth.Interface().(Person)
替换为 row := nth.Interface()
,即我删除了类型断言,那么我会得到错误:
panic: reflect: call of reflect.Value.FieldByName on interface Value
on line "field := elem.FieldByName(fieldName)
在过去的几个小时里,我尝试了很多其他的事情,比如尝试对其他一些变量进行 reflect.TypeOf()
、reflect.Indirect()
等...但没有成功。
我读过一些其他类似的问题:
Golang reflection: Can't set fields of interface wrapping a struct
他们似乎暗示我对指针或接口的工作原理没有很好的理解。
所以我的问题是,当结构被键入为接口时,我该如何设置结构的字段?
更新
我 post 编辑了一个解决方案作为答案,但我不确定它是否是正确或安全的做事方式。我希望有人能解释一下,或者post更好的解决方案。
幸运的是,我终于找到了工作。
我把我读到的一些随机的东西拼凑在一起,几乎没有韵律或原因。我什至尝试阅读 Golang 网站上的反射法则,但我认为我没有很好地理解它与为什么我不能设置类型为 interface{}
的变量之间的关系。总的来说,我还是不明白我做了什么。
我在下面的解决方案中充斥着评论,表明我很困惑,并且对我是否正确或安全地做事缺乏信心。
package main
import (
"reflect"
"log"
)
type Car struct {
Model string
}
type Person struct {
Name string
Cars []Car
}
func ModifyIt(parent interface{},fieldName string, val interface{}) {
log.Println(parent)
slice := reflect.ValueOf(parent).Elem()
nth := slice.Index(0)
row := nth.Interface()
log.Println(nth.CanSet()) // I can set this nth item
// I think I have a to make a copy, don't fully understand why this is necessary
newitem := reflect.New(reflect.ValueOf(row).Type())
newelem := newitem.Elem()
field := newelem.FieldByName(fieldName)
// I need to copy the values over from the old nth row to this new item
for c:=0; c<nth.NumField(); c++ {
newelem.Field(c).Set(reflect.Indirect(nth.Field(c)))
}
// now I can finally set the field for some reason I don't understand
field.Set(reflect.ValueOf(val).Elem())
// now that newitem has new contents in the field object, I need to overwrite the nth item with new item
// I don't know why I'm doing it, but I'll do it
// I also don't fully understand why I have to use Indirect sometimes, and not other times...it seems interchangeable with ValueOf(something).Elem(), I'm confused....
nth.Set(reflect.Indirect(newitem))
}
func main() {
p := []Person{Person{Name:"john"}}
c := []Car{Car{"corolla"},Car{"jetta"}}
ModifyIt(&p,"Cars",&c)
// now parent is up to date, although I have no idea how I got here.
log.Println(p)
}
如果有人能 post 一个更好的答案来消除我的困惑,那就太好了。我一直很难学习 golang。
试试这个:
func ModifyIt(slice interface{}, fieldName string, newVal interface{}) {
// Create a value for the slice.
v := reflect.ValueOf(slice)
// Get the first element of the slice.
e := v.Index(0)
// Get the field of the slice element that we want to set.
f := e.FieldByName(fieldName)
// Set the value!
f.Set(reflect.ValueOf(newVal))
}
这样称呼它:
p := []Person{Person{Name: "john"}}
c := []Car{Car{"corolla"}, Car{"jetta"}}
ModifyIt(p, "Cars", c)
请注意,调用直接传递切片而不是使用指向切片的指针。不需要指针并增加了额外的复杂性。
我一直在为 reflect 包苦苦挣扎。下面的代码符合我的预期:
package main
import (
"reflect"
"log"
)
type Car struct {
Model string
}
type Person struct {
Name string
Cars []Car
}
func ModifyIt(parent interface{},fieldName string, val interface{}) {
slice := reflect.ValueOf(parent).Elem()
nth := slice.Index(0)
//row := nth.Interface() // this line causes errors
row := nth.Interface().(Person)
elem := reflect.ValueOf(&row).Elem()
field := elem.FieldByName(fieldName)
log.Println(field.CanSet())
}
func main() {
p := []Person{Person{Name:"john"}}
c := []Car{Car{"corolla"},Car{"jetta"}}
ModifyIt(&p,"Cars",&c)
}
但是,如果我将行 row := nth.Interface().(Person)
替换为 row := nth.Interface()
,即我删除了类型断言,那么我会得到错误:
panic: reflect: call of reflect.Value.FieldByName on interface Value on line "field := elem.FieldByName(fieldName)
在过去的几个小时里,我尝试了很多其他的事情,比如尝试对其他一些变量进行 reflect.TypeOf()
、reflect.Indirect()
等...但没有成功。
我读过一些其他类似的问题:
Golang reflection: Can't set fields of interface wrapping a struct
他们似乎暗示我对指针或接口的工作原理没有很好的理解。
所以我的问题是,当结构被键入为接口时,我该如何设置结构的字段?
更新
我 post 编辑了一个解决方案作为答案,但我不确定它是否是正确或安全的做事方式。我希望有人能解释一下,或者post更好的解决方案。
幸运的是,我终于找到了工作。
我把我读到的一些随机的东西拼凑在一起,几乎没有韵律或原因。我什至尝试阅读 Golang 网站上的反射法则,但我认为我没有很好地理解它与为什么我不能设置类型为 interface{}
的变量之间的关系。总的来说,我还是不明白我做了什么。
我在下面的解决方案中充斥着评论,表明我很困惑,并且对我是否正确或安全地做事缺乏信心。
package main
import (
"reflect"
"log"
)
type Car struct {
Model string
}
type Person struct {
Name string
Cars []Car
}
func ModifyIt(parent interface{},fieldName string, val interface{}) {
log.Println(parent)
slice := reflect.ValueOf(parent).Elem()
nth := slice.Index(0)
row := nth.Interface()
log.Println(nth.CanSet()) // I can set this nth item
// I think I have a to make a copy, don't fully understand why this is necessary
newitem := reflect.New(reflect.ValueOf(row).Type())
newelem := newitem.Elem()
field := newelem.FieldByName(fieldName)
// I need to copy the values over from the old nth row to this new item
for c:=0; c<nth.NumField(); c++ {
newelem.Field(c).Set(reflect.Indirect(nth.Field(c)))
}
// now I can finally set the field for some reason I don't understand
field.Set(reflect.ValueOf(val).Elem())
// now that newitem has new contents in the field object, I need to overwrite the nth item with new item
// I don't know why I'm doing it, but I'll do it
// I also don't fully understand why I have to use Indirect sometimes, and not other times...it seems interchangeable with ValueOf(something).Elem(), I'm confused....
nth.Set(reflect.Indirect(newitem))
}
func main() {
p := []Person{Person{Name:"john"}}
c := []Car{Car{"corolla"},Car{"jetta"}}
ModifyIt(&p,"Cars",&c)
// now parent is up to date, although I have no idea how I got here.
log.Println(p)
}
如果有人能 post 一个更好的答案来消除我的困惑,那就太好了。我一直很难学习 golang。
试试这个:
func ModifyIt(slice interface{}, fieldName string, newVal interface{}) {
// Create a value for the slice.
v := reflect.ValueOf(slice)
// Get the first element of the slice.
e := v.Index(0)
// Get the field of the slice element that we want to set.
f := e.FieldByName(fieldName)
// Set the value!
f.Set(reflect.ValueOf(newVal))
}
这样称呼它:
p := []Person{Person{Name: "john"}}
c := []Car{Car{"corolla"}, Car{"jetta"}}
ModifyIt(p, "Cars", c)
请注意,调用直接传递切片而不是使用指向切片的指针。不需要指针并增加了额外的复杂性。