Introduction
Go has a concept called “Zero Value”, which means all variables are automatically initialized to their type’s zero value when declared. Below are examples for various types:
var i int // 0var f float64 // 0.0var b bool // falsevar s string // ""var p *int // nil
var s []ints = append(s, 1, 2, 3) // nil slice append is legal because it will allocate the underlying array automatically
var m map[string]intm["key"] = 1 // panic!nil map cannot be written to; maps must be initialized with makeCompared to C where reading an uninitialized variable can cause security vulnerabilities or crashes, or dynamic languages like JavaScript, Go automatically assigns well-defined values to avoid errors and let values be usable immediately after creation. Specifically, tags used in JSON reflection such as omitempty leverage the Zero Value concept to decide whether to omit fields:
type Response struct { ID int `json:"id"` Message string `json:"message,omitempty"` // omitted when empty string Error string `json:"error,omitempty"` // omitted when empty string}The reflect package provides IsZero() to check for zero values:
import "reflect"
func isZeroValue(v any) bool { return reflect.ValueOf(v).IsZero()}
fmt.Println(isZeroValue(0)) // truefmt.Println(isZeroValue("")) // truefmt.Println(isZeroValue(false)) // truefmt.Println(isZeroValue(42)) // falsefmt.Println(isZeroValue("hello")) // falsePractical optional-value issue
For example, the following request definition cannot distinguish between the states “false” and “not provided”:
type ConfigRequest struct { IsEnabled bool `json:"isEnabled"`}This means {"isEnabled": false} and {} are equivalent, and omitting the field may unintentionally set isEnabled to its Zero Value.
One approach is to use *bool to represent an absent value; if the field is not present it will be nil, and you can explicitly check and apply the provided value:
type ConfigRequest struct { IsEnabled *bool `json:"isEnabled"`}
if req.IsEnabled != nil { config.IsEnabled = *req.IsEnabled}