英文:
Reflect thinks struct Value is also a ptr?
问题
我有一个类似于这个示例的数据结构。如你所见,foo
包含一个指向 bar
的嵌入指针:
type foo struct {
*bar
}
type bar struct {
S []byte
}
我正在使用 reflect
包,代码如下:
func test(x interface{}) {
var v = reflect.ValueOf(x)
if v.Kind() == reflect.Struct {
fmt.Println("是一个结构体")
// 报错:reflect: 在结构体 Value 上调用 reflect.Value.Elem
// v = v.Elem()
// 报错:reflect: 在指针 Value 上调用 reflect.Value.Field
v = v.FieldByName("S")
}
}
func main() {
var f foo
test(f)
fmt.Println(string(f.S))
}
所以 v.Kind()
被识别为 reflect.Struct
,但是如果我尝试使用 .FieldByName("S")
将其视为结构体处理,它会报错,因为它认为 v
是一个指针。
然后,如果我尝试使用 .Elem()
将其视为指针处理,它又会报错,因为它认为 v
是一个结构体。
我尝试过使用 reflect.Indirect()
,以及其他一些方法,但是我无法找到如何获取嵌入指针的字段的方法。
有没有办法从嵌入指向结构体的指针中获取 reflect.Value
表示?
示例代码: http://play.golang.org/p/n0eea6XW3I
编辑: 我还尝试过 v = v.FieldByName("bar")
,但是报错如下:
panic: 运行时错误:无效的内存地址或空指针解引用
英文:
I have a data structure like this demo. As you can see, foo
has an embedded pointer to bar
:
type foo struct {
*bar
}
type bar struct {
S []byte
}
And I'm using the reflect
package like this:
func test(x interface{}) {
var v = reflect.ValueOf(x)
if v.Kind() == reflect.Struct {
fmt.Println("was a struct")
// panic: reflect: call of reflect.Value.Elem on struct Value
// v = v.Elem()
// panic: reflect: call of reflect.Value.Field on ptr Value
v = v.FieldByName("S")
}
}
func main() {
var f foo
test(f)
fmt.Println(string(f.S))
}
So v.Kind()
is recognized as a reflect.Struct
, but if I try to treat it like a struct by using .FieldByName("S")
, it panics because it thinks v
is a ptr
.
So then if I try to treat it like a ptr
by calling .Elem()
, it panics because it thinks v
is a struct
.
I've tried reflect.Indirect()
, as well as a few other things, but I can't figure out how to get the field of an embedded pointer.
Is there a way to get the reflect.Value
representation from an embedded pointer to a struct?
Demo: http://play.golang.org/p/n0eea6XW3I
EDIT: Also tried v = v.FieldByName("bar")
, but got:
><code>panic: runtime error: invalid memory address or nil pointer dereference</code>
答案1
得分: 8
我们需要意识到的第一件事是,行var f foo
等同于f := foo{}
。这将初始化内部字段bar
(类型为*bar)为其零值...即nil。嵌入类型和反射的行为似乎是将嵌入类型的字段视为类型本身的字段。因此,当您请求v.FieldByName("S")
时,它试图在f的成员bar中查找该字段,而bar为nil。
您正在尝试执行(*f.bar).S
(在Go中,不需要显式指针解引用,但这样更能说明我的观点)。现在的问题是:如果您将其更改为v.FieldByName("bar")
,为什么会出现错误?原因相同。
仔细查看堆栈跟踪,FieldByName
行不再崩溃,崩溃的是fmt.Println(string(f.S))
行。再次强调,语义上您正在执行(*f.bar).S
。但是成员"bar"为nil,因此实际上您正在进行nil指针解引用。
您可以通过将var f foo
更改为f := foo{&bar{}}
来修复这两个错误。
英文:
The first thing we need to realize is that the line var f foo
is equivalent to f := foo{}
. This initializes the internal field bar
(of type *bar) to its zero value... nil. The behavior of embedded types and reflect seems to be that it treats the embedded type's fields as fields of the type itself. So when you request v.FieldByName("S")
it's trying to find that field in f's member, bar, which is nil.
You're trying to do this (*f.bar).S
. (In Go the explicit pointer dereference isn't needed, but it makes my point). Now the question is: if you change is to v.FieldByName("bar")
why does it give an error? Same reason.
Look closely at the stack trace, the FieldByName
line no longer crashes, the line that crashes is fmt.Println(string(f.S))
. Again, semantically you're doing (*f.bar).S
. But the member "bar" is nil, so you are, in fact, doing a nil pointer dereference.
You can fix both errors by changing var f foo
to f := foo{&bar{}}
.
答案2
得分: 1
我遇到了这个错误:"panic: reflect: call of reflect.Value.Elem on struct Value",原因是这行代码:"reflect.ValueOf(parameterName).Elem()"
- 当我在反射中使用Elem()时,意味着parameterName在valueOf()内部应该是一个指向结构体的指针。
func Search(flight interface{}, key string) string {
val := reflect.ValueOf(flight).Elem()
for i := 0; i < val.NumField(); i++ {
valueField := val.Field(i)
typeField := val.Type().Field(i)
if key == strings.ToLower(typeField.Name) {
return valueField.Interface().(string)
}
}
return ""
}
现在,在调用search函数时,我的调用应该是这样的!
result := Search(&flights, key)
英文:
i was getting this error " panic: reflect: call of reflect.Value.Elem on struct Value" bcz of this line "reflect.ValueOf(parameterName).Elem()"
1.When i am using Elem() in reflex ,it means parameterName inside valueOf() should be a pointer to structure
func Search(flight interface{}, key string) string {
val := reflect.ValueOf(flight).Elem()
for i := 0; i < val.NumField(); i++ {
valueField := val.Field(i)
typeField := val.Type().Field(i)
if key == strings.ToLower(typeField.Name) {
return valueField.Interface().(string)
}
}
return ""
}
Now while calling search function my call should be like this!
result := Search(&flights, key)
通过集体智慧和协作来改善编程学习和解决问题的方式。致力于成为全球开发者共同参与的知识库,让每个人都能够通过互相帮助和分享经验来进步。
评论