Golang: How to printf % x for bytes in a struct? - go

var b [88]byte
n, err := file.Read(b[:])
fmt.Printf("bytes read: %d Bytes: [% x]\n", n, b)
The above prints bytes in hexdecimal
I have a struct like this
type SomeStruct struct {
field1 []byte
field2 []byte
}
someStructInstance := SomeStruct{[249 190 180 217], [29 1 0 0]}
fmt.Println(someStructInstance)
=> {[249 190 180 217] [29 1 0 0]}
But ideally I would like it to print hexdecimal
=> {[f9 be b4 d9] [1d 01 00 00]}
How would I go about that?

I think you will just have to define your own String function on SomeStruct. Here is an example:
package main
import "fmt"
type SomeStruct struct {
field1 []byte
field2 []byte
}
func (s SomeStruct) String() string {
return fmt.Sprintf("{[% x] [% x]}", s.field1, s.field2)
}
func main() {
someStructInstance := SomeStruct{[]byte{249, 190, 180, 217}, []byte{29, 1, 0, 0}}
fmt.Println(someStructInstance)
}
See it in running on the Go Playground: http://play.golang.org/p/eYBa1n33a2

You could use reflection to inspect the struct and print any []bytes that it has.
package main
import (
"fmt"
"reflect"
)
type SomeStruct struct {
field1 []byte
field2 []byte
}
type OtherStruct struct {
intValue int
intSlice []int
byteSlice []byte
}
var typeOfBytes = reflect.TypeOf([]byte(nil))
func printSlicesHex(obj interface{}) {
value := reflect.ValueOf(obj)
typeOfObj := value.Type()
for i := 0; i < value.NumField(); i++ {
field := value.Field(i)
if field.Type() == typeOfBytes {
bytes := field.Bytes()
printBytes(typeOfObj.Field(i).Name, bytes)
}
}
}
func printBytes(name string, bytes []byte) {
fmt.Printf("%s: [% x]\n", name, bytes)
}
func main() {
someStructInstance := SomeStruct{[]byte{249, 190, 180, 217}, []byte{29, 1, 0, 0}}
fmt.Println("Printing []bytes in SomeStruct")
printSlicesHex(someStructInstance)
fmt.Println()
otherStruct := OtherStruct{0, []int{0, 1, 2}, []byte{0, 1, 2, 3}}
fmt.Println("Printing []bytes in OtherStruct")
printSlicesHex(otherStruct)
}
For each []byte, this example prints the name of the field and its data (in hex). You could improve on this by taking a custom function to do the printing, so you don't always have to print in hex.
Playground Link

Related

variadic function in golang

package main
import (
"fmt"
)
type ISum interface {
sum() int
}
type SumImpl struct {
Num int
}
func (s SumImpl) sum() int {
return s.Num
}
func main() {
nums := []int{1, 2}
variadicExample1(nums...)
impl1 := SumImpl{Num: 1}
impl2 := SumImpl{Num: 2}
variadicExample2(impl1, impl2)
impls := []SumImpl{
{
Num: 1,
},
{
Num: 2,
},
}
variadicExample2(impls...)
}
func variadicExample1(nums ...int) {
fmt.Print(nums, " ")
total := 0
for _, num := range nums {
total += num
}
fmt.Println(total)
}
func variadicExample2(nums ...ISum) {
fmt.Print(nums, " ")
total := 0
for _, num := range nums {
total += num.sum()
}
fmt.Println(total)
}
I have a question while using variable functions in go language.
When passing a struct that implements an interface as an argument, individual declarations are possible, but can you tell me why it is not possible when passing it through ...?
An error occurs in the code below.
variadicExample2(impls...)
I read this
How to pass an interface argument to a variadic function in Golang?
var impls []ISum
impls = append(impls, impl1)
impls = append(impls, impl1)
variadicExample2(impls...)
I found that the above code is possible.
A SumImpl slice is not a ISum slice. One is a slice of structs, and the other is a slice of interfaces. That's why you cannot pass it to a function that requires a []ISum (i.e. ...ISUm).
But you can do this:
impls := []ISum{
SumImpl{
Num: 1,
},
SumImpl{
Num: 2,
},
}

Go copy bytes into struct fields with reflection

How can I iterate over a byte slice and assign them to the fields of a struct?
type s struct {
f1 []byte
f2 []byte
f3 []byte
}
func S s {
x := s{}
x.f1 = make([]byte, 4)
x.f1 = make([]byte, 2)
x.f1 = make([]byte, 2)
return x
}
func main() {
data := []byte{83, 117, 110, 83, 0, 1, 0, 65}
Z := S()
//pesudo code from here
i:= 0
for field in Z {
field = data[i:len(field)]
i += len(field)
}
Expecting:
f1 = [83,117,110,83]
f2 = [0,1]
f3 = [0,65]
I've done this in C/C++ before but I can't figure out how to do it in Go. I need the assigning function to be generic as I'm going to have several different structs some of which may not exist in the stream.
Ideally I want to pass in the initialized struct and my code would iterate over the struct fields filling them in.
Leverage the reflection code in the binary/encoding package.
Step 1: Declare the fields as arrays instead of slices.
type S struct {
F1 [4]byte
F2 [2]byte
F3 [2]byte
}
Step 2: Decode the data to the struct using binary.Read
var s S
data := []byte{83, 117, 110, 83, 0, 1, 0, 65}
err := binary.Read(bytes.NewReader(data), binary.LittleEndian, &s)
if err != nil {
log.Fatal(err)
}
Step 3: Done!
fmt.Print(s) // prints {[83 117 110 83] [0 1] [0 65]}
https://go.dev/play/p/H-e8Lusw0RC
You can use reflect.Copy. Like the built-in copy, it copies data into the destination up to its length. Make sure the fields you need to set are exported.
func main() {
data := []byte{83, 117, 110, 83, 0, 1, 0, 65}
z := S{
F1: make([]byte, 4),
F2: make([]byte, 2),
F3: make([]byte, 2),
}
SetBytes(&z, data)
fmt.Println(z) // {[83 117 110 83] [0 1] [0 65]}
}
func SetBytes(dst any, data []byte) {
v := reflect.ValueOf(dst)
if v.Kind() != reflect.Ptr {
panic("dst must be addressable")
}
v = v.Elem()
j := 0
for i := 0; i < v.NumField(); i++ {
field := v.Field(i)
if field.Kind() != reflect.Slice {
continue
}
j += reflect.Copy(v.Field(i), reflect.ValueOf(data[j:]))
}
}
Since data is assumed to be always []byte, you can subslice it directly.
Alternatively, you can use reflect.Value#Slice:
d := reflect.ValueOf(data)
// and later
j += reflect.Copy(v.Field(i), d.Slice(j, d.Len()))
Playground: https://go.dev/play/p/o1MR1qrW5pL

How to determine the element type of slice interface{}?

I have the following code to double the slice.
func doubleSlice(s []int) []int {
t := make([]int, len(s), (cap(s) + 1) * 2 )
for i := range s {
t[i] = s[i]
}
return t
}
I want to make the func to double any type of slice. And I need to know the element type first.
func showInterfaceItem(s interface{}) interface{} {
if reflect.TypeOf(s).Kind() != reflect.Slice {
fmt.Println("The interface is not a slice.")
return
}
var t interface{}
newLen := reflect.ValueOf(s).Len()
newCap := (cap(reflect.ValueOf(s).Cap()) + 1) * 2
t = make([]reflect.TypeOf(s), newLen, newCap)
return t
}
The reflect.TypeOf(s) return the type of interface{}, not the type of element. How can I get the element type of slice interface?
You can use reflect.TypeOf(s).Elem()
to get the type of element of slice.
package main
import (
"fmt"
"reflect"
)
func doubleSlice(s interface{}) interface{} {
if reflect.TypeOf(s).Kind() != reflect.Slice {
fmt.Println("The interface is not a slice.")
return nil
}
v := reflect.ValueOf(s)
newLen := v.Len()
newCap := (v.Cap() + 1) * 2
typ := reflect.TypeOf(s).Elem()
t := reflect.MakeSlice(reflect.SliceOf(typ), newLen, newCap)
reflect.Copy(t, v)
return t.Interface()
}
func main() {
xs := doubleSlice([]string{"foo", "bar"}).([]string)
fmt.Println("data =", xs, "len =", len(xs), "cap =", cap(xs))
ys := doubleSlice([]int{3, 1, 4}).([]int)
fmt.Println("data =", ys, "len =", len(ys), "cap =", cap(ys))
}
The output will be:
data = [foo bar] len = 2 cap = 6
data = [3 1 4] len = 3 cap = 8
Check it in: Go Playground
This is doable in golang and takes me whole day to discover the pattern.
Firstly, we want to get a pointer of slice to make gorm happy, which is has type "*[]Obj". To achieve that in golang, we can create a make wrapper like so:
func makeWrapper(cap uint) interface{} {
arr:= make([]Sth, 0, cap)
return &arr
}
Notice that, we can't directly reference the maked value, which might be the book keeping data need to have a stack space to store.
//Not working example
func makeWrapper(cap uint) interface{} {
return &(make([]Sth, 0, cap))
}
And as the answer before, the reflect.MakeSlice(reflect.SliceOf(typ), 0, capacity).Interface() returns interface{[]Sth}. (the typ here is refer to reflect.TypeOf(Sth{}), which equiv to typ == reflect.TypeOf(v))
Thus we need to create a return object of *[]Sth and the value inside is a slice []Sth with capacity. After understanding the objective, we can have this code:
package main
import (
"reflect"
)
type Sth struct {
a, b string
}
func main() {
af:= createSlice(Sth{})
arr := makeWrapper(10).(*[]Sth)
println(reflect.TypeOf(arr).String())
// equiv to makeWrapper, but we do it via reflection
arr = af(10).(*[]Sth)
println(reflect.TypeOf(arr).String())
}
func makeWrapper(cap uint) interface{} {
arr:= make([]Sth, 0, cap)
return &arr
}
func createSlice(v interface{}) func(int) interface{} {
var typ reflect.Type
if reflect.ValueOf(v).Kind() == reflect.Ptr {
typ = reflect.ValueOf(v).Elem().Type()
} else if reflect.ValueOf(v).Kind() == reflect.Struct {
typ = reflect.TypeOf(v)
} else {
panic("only support instance of struct or pointer of that instance")
}
return func(capacity int) interface{}{
// create the outer object saves our slice
outerObj:=reflect.New(reflect.SliceOf(typ))
// create the slice and save it to return
outerObj.Elem().Set(reflect.MakeSlice(reflect.SliceOf(typ), 0, capacity))
// retrive the interface of outer object
return outerObj.Interface()
}
}

Go: How to embed same interface twice?

Suppose we have something like this:
type ReadHandler interface {
Reader
Reader
}
Obviously, it will cause ambiguity when we call members of Reader interface on instances of ReadHandeler. So how can we achieve this in Golang?
1- Use io.MultiReader, see func MultiReader(readers ...Reader) Reader Docs:
MultiReader returns a Reader that's the logical concatenation of the
provided input readers. They're read sequentially. Once all inputs
have returned EOF, Read will return EOF. If any of the readers
return a non-nil, non-EOF error, Read will return that error.
2- or name it:
type ReadHandler interface {
Read(p []byte) (n int, err error)
Read2(p []byte) (n int, err error)
}
or:
type ReadHandler interface {
io.Reader
Read2(p []byte) (n int, err error)
}
Demonstration working sample code:
package main
import (
"errors"
"fmt"
"io"
)
func main() {
s := my{[]byte{1, 2, 3, 4, 5, 6, 7, 8, 9, 10}, []byte{10, 20, 30, 40, 50}}
buf := make([]byte, 5)
n, e := s.Read(buf)
fmt.Println(n, e, buf)
n, e = s.Read2(buf)
fmt.Println(n, e, buf)
}
type ReadHandler interface {
io.Reader
Read2(p []byte) (n int, err error)
}
type my struct {
buf []byte
buf2 []byte
}
func (t *my) Read(p []byte) (n int, err error) {
if len(p) > len(t.buf) {
return 0, errors.New("len(p)>len(buf)")
}
m := copy(p, t.buf)
return m, nil
}
func (t *my) Read2(p []byte) (n int, err error) {
if len(p) > len(t.buf2) {
return 0, errors.New("len(p)>len(buf2)")
}
m := copy(p, t.buf2)
return m, nil
}
Output:
5 <nil> [1 2 3 4 5]
5 <nil> [10 20 30 40 50]
3- name it:
Looking for a general solution to embed an interface (with any number
of methods), twice in a struct.
type my struct {
io.Reader
Rdr2 io.Reader
}
or
type my struct {
Rdrs []io.Reader
}

The binary representation of unsigned integer in Go

Is there a built-in function to convert a uint to a slice of binary integers {0,1} ?
>> convert_to_binary(2)
[1, 0]
I am not aware of such a function, however you can use strconv.FormatUint for that purpose.
Example (on play):
func Bits(i uint64) []byte {
bits := []byte{}
for _, b := range strconv.FormatUint(i, 2) {
bits = append(bits, byte(b - rune('0')))
}
return bits
}
FormatUint will return the string representation of the given uint to a base, in this case 2, so we're encoding it in binary. So the returned string for i=2 looks like this: "10". In bytes this is [49 48] as 1 is 49 and 0 is 48 in ASCII and Unicode. So we just need to iterate over the string, subtracting 48 from each rune (unicode character) and converting it to a byte.
Here is another method:
package main
import (
"bytes"
"fmt"
"math/bits"
)
func unsigned(x uint) []byte {
b := make([]byte, bits.UintSize)
for i := range b {
if bits.LeadingZeros(x) == 0 {
b[i] = 1
}
x = bits.RotateLeft(x, 1)
}
return b
}
func trimUnsigned(x uint) []byte {
return bytes.TrimLeft(unsigned(x), string(0))
}
func main() {
b := trimUnsigned(2)
fmt.Println(b) // [1 0]
}
https://golang.org/pkg/math/bits#LeadingZeros

Resources