在Go 1.19中如何从nil指针创建值

在Go 1.19中,您可能会面临这样的情况:定义了一些类型和接口,其中包括一个通用类型参数T,该参数必须是指针类型。您想要在某个特定情况下,根据nil指针的类型动态创建其底层值。本文将为您解释如何实现这一目标。

首先,让我们看一下代码示例,以更好地理解问题:

goCopy codetype A struct{}
type B struct{}

type Field interface {
    *A | *B
}

type Person[T Field] struct {
    field T
}

在上面的代码中,我们定义了两个类型A和B,还创建了一个Field接口,该接口的实现类型必须是A或B。然后,我们有一个Person结构,其字段field的类型是T,即Field接口的实例。

问题出现在do方法中,当field为nil时,我们希望能够根据T的类型动态创建其底层值。这听起来可能有些复杂,但我们可以通过使用反射和类型断言来实现这一目标。

下面是实现的代码示例:

goCopy codefunc (p Person[T]) do() {
    if p.field == nil {
        // 假设T是一个指针类型,例如*A
        pp := new(T)             // 初始化**A的实例
        rt := reflect.TypeOf(pp) // 获取**A的反射类型
        rt = rt.Elem()           // 获取*A的反射类型
        rt = rt.Elem()           // 获取A的反射类型
        rv := reflect.New(rt)    // 初始化*A的反射值
        v := rv.Interface()      // 将反射值转换为interface{}(*A)
        t := v.(T)               // 类型断言为动态类型
        p.field = t
    }
}

这段代码中,我们首先使用new函数创建了T类型的实例的指针pp。然后,通过反射,我们获取了pp的类型信息,并不断地获取其底层类型,直到我们获得了A的类型。接下来,我们使用reflect.New函数创建了A的反射值,并将其转换为interface{}类型,最后使用类型断言将其赋值给field字段。