Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Go Reflect Array

Tags:

go

reflect

The structure is like:

type Auth_msg struct {
    Msg_class       [2]byte
    Msg_content_pty [2]byte

I am fresh to use Reflect in Go and I encounter this:

panic: reflect: call of reflect.Value.Bytes on array Value

This occurs when I run val.Field(i).Bytes(), however the when I try to print it: fmt.PrintLn(val.Field(i)), it prints out the right arrays.

I just wonder, how I can retrieve the Msg_class in an array or a slice?

like image 523
Steve Yang Avatar asked Nov 22 '25 20:11

Steve Yang


1 Answers

In Go, there is a distinction between an array and a slice. Value.Bytes() explicitly works only for a byte slice (link to docs).
note : I don't know why it doesn't handle byte arrays ; it probably was written that way, and it makes the implementation of reflect.Bytes() simpler. Anyway : slices are definitely the common use case in Go, and it is easy to convert an array to a slice :


You can create a slice pointing to the array using [:] :

    v := reflect.ValueOf(msg.Msg_class)
    fmt.Println("kind :", v.Kind()) // prints 'array'
    // fmt.Printf("bytes : % x\n", v.Bytes())  // panics

    v = reflect.ValueOf(msg.Msg_class[:])
    fmt.Println("kind :", v.Kind())        // prints 'slice'
    fmt.Printf("bytes : % x\n", v.Bytes()) // works

https://play.golang.org/p/sKcGaru4rOq


To turn an array into a slice using reflect, you can call .Slice() on a reflect.Value.

One constraint, mentioned in the doc, is that the array value must be addressable.
I haven't got all the details sorted out, but one way to make sure the reflect Value is addressable is to call reflect.ValueOf() on a pointer, and then call .Elem() on that pointer value :

var arr [2]byte
arr[0] = 'g'
arr[1] = 'o'

// take ValueOf a *pointer* to your array, and let reflect dereference it :
v := reflect.ValueOf(&arr).Elem()
// this sets the "canAddr" flag on this value
fmt.Println("arr value - CanAddr() :", v.CanAddr()) // prints 'true'
slice := v.Slice(0, v.Len())
fmt.Printf("arr bytes : % x\n", slice.Bytes()) // prints '67 6f'

// for a field inside a struct : take a pointer to the struct
var msg Auth_msg
msg.Msg_class[0] = 'a'
msg.Msg_class[1] = 'z'

v = reflect.ValueOf(&msg).Elem()
fmt.Println("msg value - CanAddr() :", v.CanAddr()) // prints 'true'

// now reflect accepts to call ".Slice()" on one of its fields :
field := v.FieldByName("Msg_class")
slice = field.Slice(0, field.Len())
fmt.Printf("msg.Msg_class bytes : % x\n", slice.Bytes()) // prints '61 7a'

https://play.golang.org/p/SqM7yxl2D96

like image 114
LeGEC Avatar answered Nov 24 '25 21:11

LeGEC



Donate For Us

If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!