I have quite a few data structures that contain mostly numbers, I get the data, do a calculation and return the result.
The thing is that all of those numbers can be zero and hence, I had to switch to using pointers (*int64
or *float64
) so that the default is nil
and not 0
.
Unfortunately, I don't know of a solution to this in Go except using pointers.
The problem comes now in the Calculate()
function that is implemented for all data structures:
type X struct {
A, B, C, D, E, F *int
// and much more
Result *float64
}
func (x *X) Calculate() {
floatptr := func(f float64) *float64 { return &f }
x.Result = floatptr(float64(*x.A *x.B *x.C *x.D *x.E *x.F))
}
This function will obviously panic
if any of the data is nil
. So, I wrote the functions differently that it checks for nil
data before the calculation:
func (x *X) CalculateWithNilChecks() {
floatptr := func(f float64) *float64 { return &f }
if x.A == nil || x.B == nil || x.C == nil || x.D == nil || x.E == nil || x.F == nil {
return
}
x.Result = floatptr(float64(*x.A *x.B *x.C *x.D *x.E *x.F))
}
The problem is that the data structures are quite long. Having a SUPER long if x != nil
looks ugly. I was wondering if there is another (cleaner) way to doing this.
- I thought of doing like in the
encoding/json
and justrecover
nil pointer dereference panics, not sure if this cleaner TBH. - Another thought was to reflect the data structures and stop if any of the required data is
nil
, I don't think this should be necessary for such a simple task.
Here is a playground link for the above code
What am I missing here? Thanks!
CodePudding user response:
As general solution you can unmarshal your JSON into a map of *int
pointers or json.RawMessage
and then use a reflection to cross check with your struct or just check it with expected number of fields.
func main() {
result := make(map[string]*int)
str := `{ "A": 1, "B": 2, "C": 3, "D": 4, "E": 5, "F": 6 }`
json.Unmarshal([]byte(str), &result)
for _, field := range result {
// Check if expect fields exists using reflection or manually
// ...
}
}
CodePudding user response:
You can use reflect
module and error when one of the required fields is missing.
Use this as template.
package main
import (
"fmt"
"reflect"
)
type X struct {
A, B, C, D, E, F *int
Result *float64
}
func (x *X) PrintFoo() {
fmt.Println(x.A)
}
func main() {
a := 3
x := X{A: &a}
val := reflect.ValueOf(x)
for i := 0; i < val.Type().NumField(); i {
field := val.Type().Field(i)
fieldType := fmt.Sprintf("%s", field.Type)
if fieldType == "*int" && val.FieldByName(field.Name).IsNil() {
fmt.Println("Missing value on field", field.Name)
}
}
}