描述可变结构行为的Go类型约束

pjngdqdw  于 2023-09-28  发布在  Go
关注(0)|答案(1)|浏览(94)

我想定义一个泛型函数,其中类型约束描述可变结构行为。
我所说的“可变行为”是指这样的接口:

type Unmarshaler interface {
    Unmarshal(data []byte) error
}

...其中的实现看起来像这样:

type Foo struct {
    Content string
}

func (f *Foo) Unmarshal(data []byte) error {
    f.Content = string(data)
    return nil
}

调用接口方法会 * 改变 * 结构。
我希望能够做的是定义一个泛型函数,其中类型约束是上面的接口。泛型函数负责初始化具体类型的示例,然后使用接口方法进行变异并返回它。

func Unmarshal[T Unmarshaler](data []byte) (T, error) {
    var m T
    return m, m.Unmarshal(data)
}

所以我希望能够调用这个泛型函数,使用类型Foo。

func main() {
    foo, err := Unmarshal[*Foo]([]byte("hello"))
    if err == nil {
        log.Println(foo.Content) // hello
    } else {
        log.Fatal(err)
    }
}

我必须传递*Foo作为类型参数,因为只有指向Foo的指针实现Unmarshaler接口。但是当Foo的Unmarshal方法接收到fnil值时,就会出现这种情况。这一切对我来说都是有意义的,因为var m T将使指向Foo的指针的值为零,这是nil。但我不确定我是不是走进了死胡同?
https://go.dev/play/p/H5s59NWNiDA
正如我所能描述的,每当我的类型约束描述一些可变的结构体行为,而我的泛型函数想要初始化,然后改变结构体的示例时,我都会遇到这个问题。这可能吗?有没有更好的方法来解决这个问题?

lokaqttq

lokaqttq1#

核心问题是为某个类型T创建一个有用的值。有几种方法可以做到这一点:m := make(T)(贴图和通道)等。您可以使用reflect包来创建值,但让调用者将值作为参数传递会更简单。

func Unmarshal[T Unmarshaler](m T, data []byte) (T, error) {
    return m, m.Unmarshal(data)
}

像这样调用函数:

foo, err := Unmarshal(&Foo{}, []byte("hello"))

https://go.dev/play/p/LbSuiXe9zOu

相关问题