Можно ли написать ограничение универсального типа, чтобы тип содержал функцию, возвращающую тот же тип, или это та же проблема, что и с обычными интерфейсами? Примером использования может быть строитель с цепочечными методами.
Допустим, у меня есть конструктор IntFoo
, в котором есть метод SetFoo
, отвечающий за установку некоторого значения в поле foo
. Ссылка на игровую площадку
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] // this return type is problematic
}
и некоторая функция, использующая тип, ограниченный Builder, например:
// some generic demo function
func demo[E Builder[F], F any](builder E, foo F) {
builder.SetFoo(foo)
return
}
Попытка вызвать демонстрационную функцию
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]
Вы хотите вернуть исходный тип E
, а не интерфейс Builder
, из вашего метода:
type Builder[F, E any] interface {
SetFoo(F) E
}
а затем перерабатываем demo
, чтобы желаемый тип E
передавался в ограничение типа Builder
:
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}
связанные: Ограничение рекурсивного типа с использованием определенного типа, а не литерала типа?