Suppose you have a variable of type of the struct mentioned below which you
wanted to Unmarshal
.
type Building struct {
WindowCount int `json:"window_count"`
Doors int `json:"doors"`
}
In case the data is coming from an unreliable source, you can never be sure
that the value you will receive will always have the correct format. You
have to be cautious when working around data like this. If you are new in Go
you might be wondering what will happen you Unmarshal
and incorrect value?
Compiler Loves Zero Values
If you unmarshal the code into a variable you will get the zero value for the fields
WindowCount
, and Doors
. Which in some case can lead to bug because
you might have different logic for missing case.
var b Building
json.Unmarshal([]byte(""), &b)
fmt.Printf("%+v\n", b)
// Output:
// {WindowCount:0 Doors:0}
Pointer To Rescue 🦸
If you have worked with pointers in languages like C, C++ you might have some opinion. You either like it or you hate it. Most people fall into the later group. Working with pointers in Golang is fun because things are declarative comparatively.
If you set field type to pointer of that type it will be nil
in case the
field is missing
type Building struct {
WindowCount *int `json:"window_count"`
Doors *int `json:"doors"`
}
Unmarshalling it has the following effect:
var b Building
json.Unmarshal([]byte(`{"window_count": 2}`), &b)
fmt.Printf("%+v\n", b)
// Output:
// {WindowCount:0xc000016170 Doors:<nil>}
The WindowCount
holds the pointer to integer which holds the value 2. Whereas
since doors
is missing from the JSON string it will set to nil
thanks to
the zero value of pointers. You can now write your logic in case of the absence
of that value.
Conclusion
Since the field of a struct is part of the contract of the struct it can’t go
missing entirely instead you need to handle it little differently. Most preferable
way is to convert the type to a pointer of the same type and when in some case
the value is missing it will be set to the zero value, which is nil
.