mercredi 26 avril 2023

Having a hard time with reflection in golang

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




Aucun commentaire:

Enregistrer un commentaire