gpt4 book ai didi

Go type constraint that describes mutable struct behavior(描述可变结构行为的GO类型约束)

翻译 作者:bug小助手 更新时间:2023-10-26 21:44:01 26 4
gpt4 key购买 nike



I would like to define a generic function where the type constraint describes mutable struct behavior.

我想定义一个泛型函数,其中的类型约束描述可变的结构行为。


What I mean by a "mutable behavior", is an interface like this:

我所说的“可变行为”是如下所示的接口:


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

... where an implementation looks something like this:

...这里的实现看起来像这样:


type Foo struct {
Content string
}

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

Calling the interface method mutates the struct.

调用接口方法会使结构发生变化。


What I'd like to be able to do is define a generic function where the type constraint is the above interface. The generic function is responsible for initializing an instance of the concrete type, and then using the interface method to mutate and return it.

我想要做的是定义一个泛型函数,其中类型约束是上面的接口。泛型函数负责初始化具体类型的实例,然后使用接口方法对其进行变异并返回它。


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

So I'd like to be able to call that generic function, using the type Foo.

所以我希望能够使用foo类型调用该泛型函数。


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

I must pass *Foo as the type parameter, because only a pointer to Foo implements the Unmarshaler interface. But this panics when Foo's Unmarshal method receives a nil value for f. That all makes sense to me, since var m T is going to make a zero value of a pointer to Foo, and that is nil. But I'm not sure if I've just run into a dead end?

我必须将*foo作为类型参数传递,因为只有指向foo的指针才能实现Unmarshaler接口。但是,当foo的Unmarshal方法接收到f值为nil时,这种情况就会出现恐慌。这对我来说是有意义的,因为var mT将使指向foo的指针的值为零,而这就是零。但我不确定我是不是走进了死胡同?


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

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


As best I can describe, I run into this problem any time my type constraint describes some mutable struct behavior, and my generic function wants to initialize, then mutate, an instance of the struct. Is this possible? Is there a better way to frame this?

据我所能描述的,每当我的类型约束描述了一些可变的结构行为,并且我的泛型函数想要初始化然后变异结构的一个实例时,我都会遇到这个问题。这个是可能的吗?有没有更好的方式来框定这一点?


更多回答

There is no concept of “mutable” in an interface, you can even have non-pointer receivers with mutable data, like a slice for example. In practice you can’t really enforce how an interface is implemented, any interface could be implemented incorrectly. Structuring these types of functions like in most other libraries by passing values avoids this type of issues.

在接口中没有“可变”的概念,你甚至可以有带有可变数据的非指针接收器,比如切片。在实践中,你不能真正强制一个接口是如何实现的,任何接口都可能被错误地实现。像在大多数其他库中一样,通过传递值来构造这些类型的函数可以避免此类问题。

I get that @JimB. The mutability is in the struct implementation itself, which is what forces me to deal with a pointer to Foo. And that is why the generic function then can't initialize the appropriate type to make the method call actually work.

我明白了“吉米B”这个词。易变性在于结构实现本身,这迫使我处理指向foo的指针。这就是为什么泛型函数无法初始化适当的类型来使方法调用实际工作的原因。

优秀答案推荐

The core problem is creating a useful value for some type T. There are several ways do this: m := make(T) (maps and channels), etc. You can use reflect package to create the value, but it's simpler to have the caller pass the value as an argument.

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


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

Call the function like this:

如下所示调用该函数:


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

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

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


更多回答

Yeah, my example code simplifies my actual situation to the point where passing a value seems like a solid solution. I tried to explain that part of the context of the problem is that "my generic function wants to initialize, then mutate, an instance of the struct". Ultimately, in my situation, I can't get initialized values passed into the generic method. I drew up this other simplification that comes a little closer to what I'm actually doing, might help show why I can't initialize a value and pass it to the generic method. go.dev/play/p/0Fvnz01O7uq

是的,我的示例代码简化了我的实际情况,以至于传递值似乎是一种可靠的解决方案。我试图解释这个问题的部分上下文是“我的泛型函数想要初始化结构的一个实例,然后对其进行突变”。最终,在我的情况下,我无法将初始化值传递给泛型方法。我起草了另一个简化,它更接近于我正在做的事情,可能有助于说明为什么我不能初始化值并将其传递给泛型方法。Go.dev/play/p/0Fvnz01O7uq

Ultimately, you helped me narrow my question down to "how can a generic function initialize a useful variable for a pointer type?" And just putting that in words helps me find other questions asking basically the same thing, e.g. stackoverflow.com/questions/69573113/…

最后,您帮助我将问题缩小到“泛型函数如何初始化指针类型的有用变量?“仅仅把它用语言表达出来就可以帮助我找到其他问基本上同样问题的问题,例如stackoverflow.com/questions/69573113/.

26 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com