dimanche 22 octobre 2023

Get field of struct pointer if not nil, otherwise default value

I'm looking for a function that would reduce the redundancy in accessing a member of a struct pointer in Go. It should perform the member access if the pointer is not nil, or return a default value otherwise. It should be functionally equivalent to:

var ptr *MyStruct
var result any
if ptr != nil {
    result = ptr.MyField
} else {
    result = sql.NullFloat64{}
}

In principle, this pattern comes from the orElse of optionals in many other languages. The use case is to extract a field from a nested protobuf message and stuff it into a SQL query. The resulting function looks like the following:

func GetFieldOrElse(v any, fn string, or any) any {
    segments := strings.Split(fn, ".")
    r := reflect.ValueOf(v)
    for _, field := range segments {
        if r.IsNil() {
            return or
        }
        r = reflect.Indirect(r).FieldByName(field)
    }
    return r.Interface()
}

// pi is a protobuf message and ExtraParams is a nested message inside `pi`
GetFieldOrElse(pi.ExtraParams, "Make", sql.NullString{})
GetFieldOrElse(pi.ExtraParams, "Model", sql.NullString{})
GetFieldOrElse(pi.ExtraParams, "LensModel", sql.NullString{})
GetFieldOrElse(pi.ExtraParams, "Aperture.Numerator", sql.NullInt64{})
GetFieldOrElse(pi.ExtraParams, "Aperture.Denominator", sql.NullInt64{})

I tried to look for a compile-time solution (i.e. without reflection) but failed. Is this the idiomatic way of achieving this goal?





Aucun commentaire:

Enregistrer un commentaire