I'd just check for nil
with an if statement. It's the reasonable thing to do. Though if you want to explore alternatives, read on.
In Go 1.18 you can accomplish this with a simple generic function:
func val[T any](v *T) T {
if v != nil {
return *v
}
return *new(T) // zero value of T
}
However this works only for pointer types in the form *T
. There's other types in Go which have nil
as zero value and are not pointers. Or this function could still return nil
if you pass a pointer to such a type, like *[]int
. Unfortunately there isn't a handy way to declare a constraint for all possible nillable types1.
With Go 1.17 and below you can use a type switch if the set of possible types is known, but then have to assert the result. This has the minor advantage of permitting ad-hoc initialization of nillable types:
func val(v interface{}) interface{} {
switch t := v.(type) {
case *string:
if t != nil {
return *t
}
return ""
case *[]string:
if t != nil {
return *t
}
return []string{}
default:
panic("unexpected type")
}
}
Or just use reflection, with the same limitations of having to assert the return, or risking to return nil
again:
func val(v interface{}) interface{} {
t := reflect.TypeOf(v)
if t == nil || t.Kind() != reflect.Ptr {
panic("invalid input")
}
rv := reflect.ValueOf(v)
if rv.IsNil() {
return reflect.Zero(rv.Type().Elem()).Interface()
}
return v
}
Playground: https://go.dev/play/p/9dk0hWay90j
1: mainly because such a constraint would have to capture the key and/or value types of the map type, and decide what to (arbitrarily) return in those cases.