代码之家  ›  专栏  ›  技术社区  ›  unsafe_where_true

在戈兰反思很困难

  •  -1
  • unsafe_where_true  · 技术社区  · 3 年前

    我正在尝试动态设计一个协议测试。

    我需要使用的功能是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
    

    我不明白为什么 解码 方法处理这两者的方式不同。一个小测试程序:

    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
    

    但不知怎么的, 解码 上面,其中 内部使用反射 ,处理方式不同。

    我有什么问题?对于我的协议测试,我想定义预期输出的类型:

    type Output struct {
      Msg interface{}
    }
    

    由于消息可以是非常不同的类型,我认为唯一的方法是使用 interface{} 。因此:

    output := Output{
        Msg: MyTargetType{}.
    }
    //
    
    anotherOutput := Output{
        Msg: AnotherType{}.
    }
    // and so on
    

    以便稍后我可以检查接收到的输出是否是预期的输出。但是 解码 这种方法简直把我逼疯了。

    我试过几件有反思的事情,例如。

       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
    
    1 回复  |  直到 3 年前
        1
  •  1
  •   Bryan Newbold    3 年前

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

    output := Output{
        Msg: &MyTargetType{},  // note pointer
    }
    
    msg.Decode(output.Msg)
    

    使用反射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())