Go中如何获取指针类型的底层值?

YOU*_*YOU 1 pointers go

我发现了这个问题How to get a point to theunderlying value of an Interface{} in Go,但它对我来说看起来太不安全了。

当然,我可以用来*解压它,但我每次都必须在调用方添加 nil 检查。

x := &some_type
fmt.Println(*x)
Run Code Online (Sandbox Code Playgroud)

如果指针为零,我期望该函数返回基本类型的默认值。

x := Unpacker(some_type)
Run Code Online (Sandbox Code Playgroud)

bla*_*een 6

我只是nil用 if 语句检查一下。这是合理的做法。不过,如果您想探索替代方案,请继续阅读。

在 Go 1.18 中,您可以使用一个简单的通用函数来完成此任务:

func val[T any](v *T) T {
    if v != nil {
        return *v
    }
    return *new(T) // zero value of T
}
Run Code Online (Sandbox Code Playgroud)

然而,这仅适用于形式中的指针类型*T。Go 中还有其他类型,它们的nil值为零并且不是指针。或者,nil如果您传递指向此类类型的指针,例如*[]int. 不幸的是,没有一种方便的方法来声明所有可能为空的类型的约束1

在 Go 1.17 及更低版本中,如果可能的类型集已知,则可以使用类型开关,但必须断言结果。这样做的一个小优点是允许可空类型的临时初始化:

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")
    }
}
Run Code Online (Sandbox Code Playgroud)

或者只使用反射,具有相同的限制,必须断言返回,或者冒着nil再次返回的风险:

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
}
Run Code Online (Sandbox Code Playgroud)

游乐场:https://go.dev/play/p/9dk0hWay90j


1:主要是因为这样的约束必须捕获映射类型的键和/或值类型,并决定在这些情况下(任意)返回什么。