泛型:对返回自身的函数类型进行约束。

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

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}

huangapple
  • 本文由 发表于 2022年4月9日 01:58:40
  • 转载请务必保留本文链接:https://go.coder-hub.com/71801376.html
匿名

发表评论

匿名网友

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

确定