英文:
generics: constraint to a type with a function returning itself
问题
是否可以编写一个通用类型约束,使得该类型包含返回相同类型的函数,或者与普通接口一样存在相同的问题?一个示例用例是具有可链接方法的构建器。
假设我有一个名为IntFoo
的构建器,它有一个名为SetFoo
的方法,负责将foo
字段设置为某个值。Playground链接
type IntFoo struct {
foo int
}
func (me *IntFoo) SetFoo(foo int) *IntFoo {
me.foo = foo
return me
}
现在我可能有几个类似这样的具有不同类型的构建器,我想定义一个类似这样的约束:
type Builder[F any] interface {
SetFoo(F) Builder[F] // 这个返回类型有问题
}
以及一些消费符合Builder约束的类型的函数,如下所示:
// 一些通用演示函数
func demo[E Builder[F], F any](builder E, foo F) {
builder.SetFoo(foo)
return
}
尝试调用demo函数
e := &IntFoo{}
demo(e, 2)
会导致错误:
[compiler InvalidTypeArg] [E] *IntFoo does not implement Builder[int] (wrong type for method SetFoo)
have SetFoo(foo int) *IntFoo
want SetFoo(int) Builder[int]
英文:
Is it possible to write a generic type constraint so that the type contains a function returning the same type or is it the same problem as with normal interfaces? Example use-case would be a builder with chainable methods.
Let's say I have a builder IntFoo
which has a SetFoo
method responsible for setting the foo
field to some value. Playground link
type IntFoo struct {
foo int
}
func (me *IntFoo) SetFoo(foo int) *IntFoo {
me.foo = foo
return me
}
Now I might have several builders like this one with different types and I'd like to define a constraint like this:
type Builder[F any] interface {
SetFoo(F) Builder[F] // this return type is problematic
}
and some function consuming the Builder-constrained type like so:
// some generic demo function
func demo[E Builder[F], F any](builder E, foo F) {
builder.SetFoo(foo)
return
}
Trying to call the demo function
e := &IntFoo{}
demo(e, 2)
results in an error:
[compiler InvalidTypeArg] [E] *IntFoo does not implement Builder[int] (wrong type for method SetFoo)
have SetFoo(foo int) *IntFoo
want SetFoo(int) Builder[int]
答案1
得分: 3
你想从你的方法中返回原始类型E
,而不是Builder
接口。然后重新调整demo
函数,以便将所需的类型E
传递给Builder
类型约束。
type Builder[F, E any] interface {
SetFoo(F) E
}
func demo[E Builder[F, E], F any](bldr E, foo F) E {
return bldr.SetFoo(foo)
}
v := demo(e, 2)
fmt.Printf("%[1]T : %+[1]v\n", v) // *main.IntFoo : &{foo:2}
链接:https://go.dev/play/p/2K4D_nzMwU2
英文:
You want to return the original type E
- not the Builder
interface - from your method:
type Builder[F, E any] interface {
SetFoo(F) E
}
and then reworking demo
, so the desired type E
is relayed to the Builder
type constraint:
func demo[E Builder[F, E], F any](bldr E, foo F) E {
return bldr.SetFoo(foo)
}
https://go.dev/play/p/2K4D_nzMwU2
v := demo(e, 2)
fmt.Printf("%[1]T : %+[1]v\n", v) // *main.IntFoo : &{foo:2}
通过集体智慧和协作来改善编程学习和解决问题的方式。致力于成为全球开发者共同参与的知识库,让每个人都能够通过互相帮助和分享经验来进步。
评论