英文:
Having a hard time with reflection in golang
问题
我正在尝试动态设计一个协议测试。
我需要使用的函数是go-ethereum的Decode
:
https://github.com/ethereum/go-ethereum/blob/master/p2p/message.go#L54
然后我的一些代码使用它:
msg <- receive() //发送给我一个类型为p2p.Msg的消息
var message MyTargetType
msg.Decode(&message) //这个工作正常,这显然是使用函数的正确方式,使用变量的指针
anotherMessage := output.Msg //这是一个interface{},见下面
msg.Decode(&anotherMessage) //这个失败了
我不明白为什么Decode
方法处理这两个不同。一个小测试程序:
package main
import (
"fmt"
"reflect"
)
type mystruct struct {
hello string
}
func main() {
var first mystruct
second := mystruct{}
fmt.Println(reflect.TypeOf(first))
fmt.Println(reflect.TypeOf(second))
}
这将打印相同的类型:
main.mystruct
main.mystruct
但是不知何故,上面的Decode
,它在内部使用反射,却以不同的方式处理它们。
我的问题是什么?对于我的协议测试,我想定义预期的输出类型:
type Output struct {
Msg interface{}
}
由于消息的类型可能非常不同,我认为唯一的方法是使用interface{}
。因此:
output := Output{
Msg: MyTargetType{}.
}
//
anotherOutput := Output{
Msg: AnotherType{}.
}
//等等
这样,我稍后可以检查接收到的输出是否符合预期。但是,那个Decode
方法让我发疯。
我尝试了几种使用反射的方法,例如:
var decodedMsg = reflect.TypeOf(output.Msg)
msg.Decode(&decodedMsg)
甚至是
var decodedMsg = reflect.New(reflect.TypeOf(output.Msg)).Elem().Interface()
fmt.Println(reflect.TypeOf(decodedMsg)) //这实际上打印出了正确的类型!!!
// 但是Decode仍然失败,显示:
// 给Decode的接口必须是指针
英文:
I am trying to dynamically design a protocol test.
The function which I need to use is go-ethereum's Decode
:
https://github.com/ethereum/go-ethereum/blob/master/p2p/message.go#L54
Then some of my code uses it:
msg <- receive() //sends me a message of type p2p.Msg
var message MyTargetType
msg.Decode(&message) // this works correctly and this is apparently the correct way to use the function, with a pointer to the variable
anotherMessage := output.Msg // this is an interface{}, see below
msg.Decode(&anotherMessage) // this fails
I don't understand why the Decode
method handles the two differently. A little test program:
package main
import (
"fmt"
"reflect"
)
type mystruct struct {
hello string
}
func main() {
var first mystruct
second := mystruct{}
fmt.Println(reflect.TypeOf(first))
fmt.Println(reflect.TypeOf(second))
}
This prints the types to be the same:
main.mystruct
main.mystruct
But somehow, Decode
above, which uses reflection internally, handles them differently.
What's my problem? For my protocol test, I want to define the type of the output to be expected:
type Output struct {
Msg interface{}
}
Since the messages can be of very different type, I thought the only way is to use interface{}
. Therefore:
output := Output{
Msg: MyTargetType{}.
}
//
anotherOutput := Output{
Msg: AnotherType{}.
}
// and so on
so that I then later can check that the output received is the one expected. But that Decode
method is driving me crazy.
I have tried several things with reflection, e.g.
var decodedMsg = reflect.TypeOf(output.Msg)
msg.Decode(&decodedMsg)
or even
var decodedMsg = reflect.New(reflect.TypeOf(output.Msg)).Elem().Interface()
fmt.Println(reflect.TypeOf(decodedMsg)) //this actually prints the correct type!!!
// But then Decode fails nonetheless with:
// interface given to Decode must be a pointer
答案1
得分: 1
将Decode的参数改为指向目标类型的指针。使用以下代码:
output := Output{
Msg: &MyTargetType{}, // 注意指针
}
msg.Decode(output.Msg)
使用反射API处理任何类型:
output := Output{
Msg: MyTargetType{},
}
...
// 分配新值。
v := reflect.New(reflect.TypeOf(output.Msg))
// 解码到该值。注意v是指向新值的指针。
msg.Decode(v.Interface()))
// 将新值赋给字段。
reflect.ValueOf(&output.Msg).Elem().Set(v.Elem())
英文:
The argument to Decode must be a pointer to the target type. Use this code:
output := Output{
Msg: &MyTargetType{}, // note pointer
}
msg.Decode(output.Msg)
Use the reflect API to handle any type:
output := Output{
Msg: MyTargetType{},
}
...
// Allocate new value.
v := reflect.New(reflect.TypeOf(output.Msg))
// Decode to that value. Note that v has pointer to new value.
msg.Decode(v.Interface()))
// Assign new value to field.
reflect.ValueOf(&output.Msg).Elem().Set(v.Elem())
通过集体智慧和协作来改善编程学习和解决问题的方式。致力于成为全球开发者共同参与的知识库,让每个人都能够通过互相帮助和分享经验来进步。
评论