Follow

Keep Up to Date with the Most Important News

By pressing the Subscribe button, you confirm that you have read and are agreeing to our Privacy Policy and Terms of Use
Contact

What is the idiomatic way of getting underlying value of pointer type in Go?

I found this question How to get a pointer to the underlying value of an Interface{} in Go, but it looks like 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 if it is nil.

MEDevel.com: Open-source for Healthcare and Education

Collecting and validating open-source software for healthcare, education, enterprise, development, medical imaging, medical records, and digital pathology.

Visit Medevel

x := Unpacker(some_type)

>Solution :

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.

Add a comment

Leave a Reply

Keep Up to Date with the Most Important News

By pressing the Subscribe button, you confirm that you have read and are agreeing to our Privacy Policy and Terms of Use

Discover more from Dev solutions

Subscribe now to keep reading and get access to the full archive.

Continue reading