convert string to fixed size byte array in Go - go

Is there convenient way for initial a byte array?
package main
import "fmt"
type T1 struct {
f1 [5]byte // I use fixed size here for file format or network packet format.
f2 int32
}
func main() {
t := T1{"abcde", 3}
// t:= T1{[5]byte{'a','b','c','d','e'}, 3} // work, but ugly
fmt.Println(t)
}
prog.go:8: cannot use "abcde" (type string) as type [5]uint8 in field value
if I change the line to t := T1{[5]byte("abcde"), 3}
prog.go:8: cannot convert "abcde" (type string) to type [5]uint8

You could copy the string into a slice of the byte array:
package main
import "fmt"
type T1 struct {
f1 [5]byte
f2 int
}
func main() {
t := T1{f2: 3}
copy(t.f1[:], "abcde")
fmt.Println(t)
}
Edit: using named form of T1 literal, by jimt's suggestion.

Is there any particular reason you need a byte array? In Go you will be better off using a byte slice instead.
package main
import "fmt"
type T1 struct {
f1 []byte
f2 int
}
func main() {
t := T1{[]byte("abcde"), 3}
fmt.Println(t)
}

Related

Remove an interface item from a slice

I want to remove an item in a slice w/o having to use a specific function for every type of items in the slice. So, I am using interface{} as the slice item type:
package main
import "fmt"
func sliceRemoveItem(slice []interface{}, s int) []interface{} {
return append(slice[:s], slice[s+1:]...)
}
func main() {
array := []int{1,2,3,4,5,6,7}
fmt.Println(array)
fmt.Println(sliceRemoveItem(array,1))
}
But goLang doesn't like it:
./prog.go:13:30: cannot use array (type []int) as type []interface {} in argument to sliceRemoveItem
https://play.golang.org/p/wUrR5iGRZ5Y
Any idea how to do this? Is it possible to use a generic single function accepting any type of slice items?
Refs: How to delete an element from a Slice in Golang
You're trying to pass a slice of int as a slice of interface{}. Go doesn't do this conversion implicitly since it is a costly operation.
Check out this answer: https://stackoverflow.com/a/12754757
You can either accept []interface{}, but do the conversion explicitly, or specify the type as []int. This works:
package main
import "fmt"
func sliceRemoveItem(slice []int, s int) []int {
return append(slice[:s], slice[s+1:]...)
}
func main() {
array := []int{1,2,3,4,5,6,7}
fmt.Println(array)
fmt.Println(sliceRemoveItem(array,1))
}
Use the reflect package.
// sliceRemoveItem removes item at index i from the
// slice pointed to by slicep.
func sliceRemoveItem(slicep interface{}, i int) {
v := reflect.ValueOf(slicep).Elem()
v.Set(reflect.AppendSlice(v.Slice(0, i), v.Slice(i+1, v.Len())))
}
Call it like this:
slice := []int{1, 2, 3, 4, 5, 6, 7}
sliceRemoveItem(&slice, 1)
To avoid type assertions in the caller, the function uses a pointer to slice argument.
Run it on the Go playground

How to omit conditional field of struct within marshal

There is struct of MyStruct.
type MyStruct struct {
Code int `json:"Code"`
Flags uint8 `json:"Flags"`
OptionField int `json:",omitempty"`
}
Following code convert it to json.
f := MyStruct{Code:500, OptionField:41}
r, _ := json.Marshal(f)
fmt.Println(string(r)
I need to "OptionField" be optional. Some time it should exist in json with one of values [0, 1, 2, 3, ]. and in the other time it should exclude from json.
My problem is: omitempty will exclude it when the value is zero, and the default value of int is zero. Is there any way to omit field in condition (ex: omit if value is -1). Or there is any way to do it.
You could use *int instead of int and set the pointer value to nil in order to omit this.
package main
import (
"encoding/json"
"fmt"
)
type MyStruct struct {
Code int `json:"Code"`
Flags uint8 `json:"Flags"`
OptionField *int `json:",omitempty"`
}
func format(s MyStruct) string {
r, _ := json.Marshal(s)
return string(r)
}
func main() {
f := MyStruct{Code: 500, Flags: 10, OptionField: new(int)}
fmt.Println(format(f)) // {"Code":500,"Flags":10,"OptionField":0}
f.OptionField = nil
fmt.Println(format(f)) // {"Code":500,"Flags":10}
}

How can I parse []int JSON data in Go?

I try parse JSON data include integer array. But, I can't get integer array.
package main
import (
"encoding/json"
"fmt"
)
type Anything struct {
A []int `json:"a"`
}
func main() {
s := "{a:[1,2,3]}"
var a Anything
json.Unmarshal([]byte(s), &a)
fmt.Println(a.A)
}
I got empty array.
[]
How can I get [1, 2, 3]?
{a:[1,2,3]} is not valid JSON. Object keys must be double-quoted. Changing it like this works as expected:
s := "{\"a\":[1,2,3]}"
https://play.golang.org/p/qExZAeiRJy
You have an invalid JSON. You should replace it, for example like this: s := [{"a":[1,2,3]}] or maybe like this s := "[{\"a\":[1,2,3]}]".
You can edit your code to something like this:
package main
import (
"encoding/json"
"fmt"
)
type Anything struct {
A []int `json:"a"`
}
func main() {
// note here: `[{"a":[1,2,3]}]`
// or: s := "[{\"a\":[1,2,3]}]"
s := `[{"a":[1,2,3]}]`
var a []Anything
json.Unmarshal([]byte(s), &a)
fmt.Println(a)
}
Output:
[{[1 2 3]}]
You can run it on https://play.golang.org/p/H4GupGFpfP

Get rid of empty JSON values from map of interface{}

I have a struct in which I put all excess data into a map[string]interface{}.
If I unmarshal into the Data property with an empty variable, I don't want to keep it when marshalling. I basically need interface{} to have json:",omitempty", How do I get that?
type Event struct {
From string `json:"from"`
Data map[string]interface{} `json:"data,omitempty"`
}
The omitempty is for encoding values, but not for decoding.
You cannot generate a complete empty map in Go. (Empty as in, it does not exists.) If your create a variable / value of a struct it always has its default value.
package main
import "fmt"
func main() {
var m map[string]interface{}
fmt.Printf("%v %d\n", m, len(m))
// prints: map[] 0
m = nil
fmt.Printf("%v %d\n", m, len(m))
// prints: map[] 0
}
Example: Go Playground.
I'd like to know if there's anything native that supports it. However until then, you can do it via reflection:
package main
import (
"encoding/json"
"fmt"
"reflect"
)
func main() {
m := map[string]interface{}{
"should_exist": "foo",
"should_omit": "",
}
for k, v := range m {
if reflect.ValueOf(v).IsZero() {
delete(m, k)
}
}
data, _ := json.Marshal(m)
fmt.Println(string(data)) // {"should_exist":"foo"}
}
Please note the performance hit this might cause in some use cases.

How to get a list of values into a flag in Golang?

What is Golang's equivalent of the below python commands ?
import argparse
parser = argparse.ArgumentParser(description="something")
parser.add_argument("-getList1",nargs='*',help="get 0 or more values")
parser.add_argument("-getList2",nargs='?',help="get 1 or more values")
I have seen that the flag package allows argument parsing in Golang.
But it seems to support only String, Int or Bool.
How to get a list of values into a flag in this format :
go run myCode.go -getList1 value1 value2
You can define your own flag.Value and use flag.Var() for binding it.
The example is here.
Then you can pass multiple flags like following:
go run your_file.go --list1 value1 --list1 value2
UPD: including code snippet right there just in case.
package main
import "flag"
type arrayFlags []string
func (i *arrayFlags) String() string {
return "my string representation"
}
func (i *arrayFlags) Set(value string) error {
*i = append(*i, value)
return nil
}
var myFlags arrayFlags
func main() {
flag.Var(&myFlags, "list1", "Some description for this param.")
flag.Parse()
}
You can at least have a list of arguments on the end of you command by using the flag.Args() function.
package main
import (
"flag"
"fmt"
)
var one string
func main() {
flag.StringVar(&one, "o", "default", "arg one")
flag.Parse()
tail := flag.Args()
fmt.Printf("Tail: %+q\n", tail)
}
my-go-app -o 1 this is the rest will print Tail: ["this" "is" "the" "rest"]
Use flag.String() to get the entire list of values for the argument you need and then split it up into individual items with strings.Split().
If you have a series of integer values at the end of the command line, this helper function will properly convert them and place them in a slice of ints:
package main
import (
"flag"
"fmt"
"strconv"
)
func GetIntSlice(i *[]string) []int {
var arr = *i
ret := []int{}
for _, str := range arr {
one_int, _ := strconv.Atoi(str)
ret = append(ret, one_int)
}
return ret
}
func main() {
flag.Parse()
tail := flag.Args()
fmt.Printf("Tail: %T, %+v\n", tail, tail)
intSlice := GetIntSlice(&tail)
fmt.Printf("intSlice: %T, %+v\n", intSlice, intSlice)
}
mac:demoProject sx$ go run demo2.go 1 2 3 4
Tail: []string, [1 2 3 4]
intSlice: []int, [1 2 3 4]

Resources