在golang中很难处理反射

64jmpszr  于 2023-04-27  发布在  Go
关注(0)|答案(1)|浏览(68)

我正在尝试动态设计一个协议测试。
我需要使用的函数是go-ethereum的Decode:https://github.com/ethereum/go-ethereum/blob/master/p2p/message.go#L54
然后我的一些代码使用它:

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

我不明白为什么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{}.
}
// and so on

这样我以后就可以检查接收到的输出是否是预期的输出。但是那个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)) //this actually prints the correct type!!! 
   // But then Decode fails nonetheless with:
   // interface given to Decode must be a pointer
vom3gejh

vom3gejh1#

Decode的参数必须是指向目标类型的指针。使用以下代码:

output := Output{
    Msg: &MyTargetType{},  // note pointer
}

msg.Decode(output.Msg)

使用reflect API处理任何类型:

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())

相关问题