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

huangapple go评论77阅读模式
英文:

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

问题

我找到了这个问题https://stackoverflow.com/questions/57696977/how-to-get-a-pointer-to-the-underlying-value-of-an-interface-in-go,但是对我来说看起来太不安全了。

当然,我可以使用*来解包它,但是每次在调用方都需要添加nil检查。

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

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

x := Unpacker(some_type)
英文:

I found this question https://stackoverflow.com/questions/57696977/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)

答案1

得分: 6

我只会翻译你提供的内容,以下是翻译好的部分:

我只是用一个if语句检查nil。这是合理的做法。不过,如果你想探索其他选择,可以继续阅读。

在Go 1.18中,你可以通过一个简单的泛型函数来实现:

func val[T any](v *T) T {
    if v != nil {
        return *v
    }
    return *new(T) // T的零值
}

然而,这仅适用于形式为*T的指针类型。Go中还有其他具有nil作为零值且不是指针的类型。或者,如果你传递一个指向这种类型的指针(如*[]int),这个函数仍然可能返回nil。不幸的是,目前没有一种方便的方法来声明适用于所有可能的可为空类型的约束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")
    }
}

或者使用反射,但同样需要断言返回值,否则可能再次返回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
}

Playground: https://go.dev/play/p/9dk0hWay90j


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

英文:

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 types<sup>1</sup>.

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 &quot;&quot;

    case *[]string:
        if t != nil {
            return *t
        }
        return []string{}

    default:
        panic(&quot;unexpected type&quot;)
    }
}

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(&quot;invalid input&quot;)
    }
    rv := reflect.ValueOf(v)
    if rv.IsNil() {
        return reflect.Zero(rv.Type().Elem()).Interface()
    }
    return v
}

Playground: https://go.dev/play/p/9dk0hWay90j

<hr>

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.

答案2

得分: 0

我接受另一个答案,但是这是我尝试过的,显然对于基本类型也有效。

func Unwrap[T any](x *T) (r T) {
    if x != nil {
        r = *x
    }
    return
}
英文:

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
}

huangapple
  • 本文由 发表于 2022年7月14日 14:01:32
  • 转载请务必保留本文链接:https://go.coder-hub.com/72975880.html
匿名

发表评论

匿名网友

:?: :razz: :sad: :evil: :!: :smile: :oops: :grin: :eek: :shock: :???: :cool: :lol: :mad: :twisted: :roll: :wink: :idea: :arrow: :neutral: :cry: :mrgreen:

确定