How to omit conditional field of struct within marshal - go

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}
}

Related

Using reflect, how to set value to a struct field (pointer)

I try to set value to a struct field (pointer field) by reflect, but failed.
I get the name of a struct field, so use FieldByName to get the field
The field is a pointer.
I try to use FieldByName().Set FieldByName().SetPointer to set value.
type t struct {
b *int
}
func main() {
t := new(ts)
a := new(int)
ss := reflect.ValueOf(t).FieldByName("b").Set(a)
}
type t struct {
b *int
}
func main() {
t := new(ts)
a := new(int)
ss := reflect.ValueOf(t).FieldByName("b").SetPointer(a)
}
First code:
=======>
./test.go:14:50: cannot use a (type *int) as type reflect.Value in argument to reflect.ValueOf(t).FieldByName("b").Set
./test.go:14:50: reflect.ValueOf(t).FieldByName("b").Set(a) used as value
Second code:
=======>
./test.go:14:57: cannot use a (type *int) as type unsafe.Pointer in argument to reflect.ValueOf(t).FieldByName("b").SetPointer
./test.go:14:57: reflect.ValueOf(t).FieldByName("b").SetPointer(a) used as value
I want to use reflect to make the pointer field (name "b") alloced a space and set a value.
type ts struct {
B *int //field must be exported
}
func main() {
var t ts
foo := 5
a := &foo
//Use Elem() to indirect through the pointer and get struct field
//Use reflect.ValueOf(a) to satisfy Set() signature
reflect.ValueOf(&t).Elem().FieldByName("B").Set(reflect.ValueOf(a))
fmt.Println(*t.B)
}
Playground https://play.golang.org/p/gZt0ahTZMIi

Cannot convert time.Now() to a string

I have this struct:
// Nearby whatever
type Nearby struct {
id int `json:"id,omitempty"`
me int `json:"me,omitempty"`
you int `json:"you,omitempty"`
contactTime string `json:"contactTime,omitempty"`
}
and then I call this:
strconv.Itoa(time.Now())
like so:
s1 := Nearby{id: 1, me: 1, you: 2, contactTime: strconv.Itoa(time.Now())}
but it says:
> cannot use time.Now() (type time.Time) as type int in argument to
> strconv.Itoa
does anyone know what that's about? I am trying to convert an int to a string here.
does anyone know what that's about? I am trying to convert an int to a string here.
Time type is not equivalent to an int. If your need is a string representation, type Time has a String() method.
Sample code below (also available as a runnable Go Playground snippet):
package main
import (
"fmt"
"time"
)
// Nearby whatever
type Nearby struct {
id int
me int
you int
contactTime string
}
func main() {
s1 := Nearby{
id: 1,
me: 1,
you: 2,
contactTime: time.Now().String(), // <-- type Time has a String() method
}
fmt.Printf("%+v", s1)
}
Hope this helps. Cheers,

Looping over slice of aliased(user defined) types gives type before aliasing

I'm trying to loop over slice of user defined types (in example below these are aliased int), but range produces values of type int, instead of MyInt as I would expect. Casting inside 'if' helps for sure, but I would like to understand why range does not produces values of type MyInt.
package main
import (
"fmt"
)
type MyInt int
const (
MYINT00 MyInt = iota
MYINT01
)
func main() {
var myInt02 MyInt = 2
myInts := []MyInt{MYINT00, MYINT01}
for i := range myInts {
if i == myInt02 {
fmt.Println("same")
}
}
}
Playground: https://play.golang.org/p/nb77pvTMdkW
Error:
prog.go:18:8: invalid operation: i == myInt02 (mismatched types int and MyInt)
Then I thought that problem can be related to consts and iota, so I used variables declared in function - didn't change anything.
https://play.golang.org/p/0fVRhBtvlOL
https://play.golang.org/p/pioDSU4oJdP
I haven't found any info in Effective Go/other questions. If anybody has some input on that, please share!
The Go Programming Language Specification
For statements with range clause
Range expression 1st value 2nd value
array or slice a [n]E, *[n]E, or []E index i int a[i] E
i is the range index, an int, not the range value.
For example, fixing your code to use the range value,
package main
import (
"fmt"
)
type MyInt int
const (
MYINT00 MyInt = iota
MYINT01
)
func main() {
var myInt02 MyInt = 2
myInts := []MyInt{MYINT00, MYINT01}
for _, v := range myInts {
if v == myInt02 {
fmt.Println("same")
}
}
}

How to access unexported struct fields

Is there a way to use reflect to access unexported fields in Go 1.8?
This no longer seems to work: https://stackoverflow.com/a/17982725/555493
Note that reflect.DeepEqual works just fine (that is, it can access unexported fields) but I can't make heads or tails of that function. Here's a go playarea that shows it in action: https://play.golang.org/p/vyEvay6eVG. The src code is below
import (
"fmt"
"reflect"
)
type Foo struct {
private string
}
func main() {
x := Foo{"hello"}
y := Foo{"goodbye"}
z := Foo{"hello"}
fmt.Println(reflect.DeepEqual(x,y)) //false
fmt.Println(reflect.DeepEqual(x,z)) //true
}
If the struct is addressable, you can use unsafe.Pointer to access the field (read or write) it, like this:
rs := reflect.ValueOf(&MyStruct).Elem()
rf := rs.Field(n)
// rf can't be read or set.
rf = reflect.NewAt(rf.Type(), unsafe.Pointer(rf.UnsafeAddr())).Elem()
// Now rf can be read and set.
See full example on the playground.
This use of unsafe.Pointer is valid according to the documentation and running go vet returns no errors.
If the struct is not addressable this trick won't work, but you can create an addressable copy like this:
rs = reflect.ValueOf(MyStruct)
rs2 := reflect.New(rs.Type()).Elem()
rs2.Set(rs)
rf = rs2.Field(0)
rf = reflect.NewAt(rf.Type(), unsafe.Pointer(rf.UnsafeAddr())).Elem()
// Now rf can be read. Setting will succeed but only affects the temporary copy.
See full example on the playground.
Based on cpcallen's work:
import (
"reflect"
"unsafe"
)
func GetUnexportedField(field reflect.Value) interface{} {
return reflect.NewAt(field.Type(), unsafe.Pointer(field.UnsafeAddr())).Elem().Interface()
}
func SetUnexportedField(field reflect.Value, value interface{}) {
reflect.NewAt(field.Type(), unsafe.Pointer(field.UnsafeAddr())).
Elem().
Set(reflect.ValueOf(value))
}
reflect.NewAt might be confusing to read at first. It returns a reflect.Value representing a pointer to a value of the specified field.Type(), using unsafe.Pointer(field.UnsafeAddr()) as that pointer. In this context reflect.NewAt is different than reflect.New, which would return a pointer to a freshly initialized value.
Example:
type Foo struct {
unexportedField string
}
GetUnexportedField(reflect.ValueOf(&Foo{}).Elem().FieldByName("unexportedField"))
https://play.golang.org/p/IgjlQPYdKFR
reflect.DeepEqual() can do it because it has access to unexported features of the reflect package, in this case namely for the valueInterface() function, which takes a safe argument, which denies access to unexported field values via the Value.Interface() method if safe=true. reflect.DeepEqual() will (might) call that passing safe=false.
You can still do it, but you cannot use Value.Interface() for unexported fields. Instead you have to use type-specific methods, such as Value.String() for string, Value.Float() for floats, Value.Int() for ints etc. These will return you a copy of the value (which is enough to inspect it), but will not allow you to modify the field's value (which might be "partly" possible if Value.Interface() would work and the field type would be a pointer type).
If a field happens to be an interface type, you may use Value.Elem() to get to the value contained / wrapped by the interface value.
To demonstrate:
type Foo struct {
s string
i int
j interface{}
}
func main() {
x := Foo{"hello", 2, 3.0}
v := reflect.ValueOf(x)
s := v.FieldByName("s")
fmt.Printf("%T %v\n", s.String(), s.String())
i := v.FieldByName("i")
fmt.Printf("%T %v\n", i.Int(), i.Int())
j := v.FieldByName("j").Elem()
fmt.Printf("%T %v\n", j.Float(), j.Float())
}
Output (try it on the Go Playground):
string hello
int64 2
float64 3
package main
import (
"fmt"
"reflect"
"strings"
"unsafe"
)
type Person1 struct {
W3ID string
Name string
}
type Address1 struct {
city string
country string
}
type User1 struct {
name string
age int
address Address1
manager Person1
developer Person1
tech Person1
}
func showDetails(load, email interface{}) {
if reflect.ValueOf(load).Kind() == reflect.Struct {
typ := reflect.TypeOf(load)
value := reflect.ValueOf(load)
//#1 For struct, not addressable create a copy With Element.
value2 := reflect.New(value.Type()).Elem()
//#2 Value2 is addressable and can be set
value2.Set(value)
for i := 0; i < typ.NumField(); i++ {
if value.Field(i).Kind() == reflect.Struct {
rf := value2.Field(i)
/* #nosec G103 */
rf = reflect.NewAt(rf.Type(), unsafe.Pointer(rf.UnsafeAddr())).Elem()
irf := rf.Interface()
typrf := reflect.TypeOf(irf)
nameP := typrf.String()
if strings.Contains(nameP, "Person") {
//fmt.Println(nameP, "FOUND !!!!!!! ")
for j := 0; j < typrf.NumField(); j++ {
re := rf.Field(j)
nameW := typrf.Field(j).Name
if strings.Contains(nameW, "W3ID") {
valueW := re.Interface()
fetchEmail := valueW.(string)
if fetchEmail == email {
fmt.Println(fetchEmail, " MATCH!!!!")
}
}
}
}
showDetails(irf, email)
} else {
// fmt.Printf("%d.Type:%T || Value:%#v\n",
// (i + 1), value.Field(i), value.Field(i))
}
}
}
}
func main() {
iD := "tsumi#in.org.com"
load := User1{
name: "John Doe",
age: 34,
address: Address1{
city: "New York",
country: "USA",
},
manager: Person1{
W3ID: "jBult#in.org.com",
Name: "Bualt",
},
developer: Person1{
W3ID: "tsumi#in.org.com",
Name: "Sumi",
},
tech: Person1{
W3ID: "lPaul#in.org.com",
Name: "Paul",
},
}
showDetails(load, iD)
}

convert string to fixed size byte array in 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)
}

Resources