Home > Blockchain >  How to get the underlying value of pointer type in Go?
How to get the underlying value of pointer type in Go?

Time:07-14

I found this question How to get a pointer to the underlying value of an Interface{} in Go, but it looks too unsafe for me.

Of course I could use * to unpack it but I have to add nil check every time on caller side.

x := &some_type
fmt.Println(*x)

I am expecting the function that return default value of the base type if the pointer is nil.

x := Unpacker(some_type)

CodePudding user response:

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.

CodePudding user response:

I am accepting another answer, but here is what I tried which apparently work for primitives too.

func Unwrap[T any](x *T) (r T) {
    if x != nil {
        r = *x
    }
    return
}
  • Related