实现接口的指针的泛型类型是什么?
What is the generic type for a pointer that implements an interface?
我有这样的界面
type A interface {
SomeMethod()
}
我通过结构指针实现了这个接口:
type Aimpl struct {}
func (a *Aimpl) SomeMethod() {}
我有一个通用函数,它接受一个带有 A 参数的函数,如下所示:
func Handler[T A](callback func(result T)) {
// Essentially what I'd like to do is result := &Aimpl{} (or whatever T is)
callback(result)
}
我还应该补充一点,我不能修改 A
的定义(它来自图书馆)。我试过这个:
type MyA[T any] interface{
A
*T
}
但是这段代码给我一个错误:
func Handler[P any, T MyA[P]](callback func(result A)) {
result := new(P)
callback(result) // result does not implement interface. It's a pointer to a type, not a type
}
您可以使用类型参数声明接口,使其要求实现它的类型是指向其类型参数的指针。
type A[P any] interface {
SomeMethod()
*P
}
因此,您还需要稍微修改处理程序的签名。
func Handler[P any, T A[P]](callback func(result T)) {
result := new(P)
callback(result)
}
Handler(func(a *Aimpl) { fmt.Printf("%#v\n", a) })
https://go.dev/play/p/PY5iE7WoHt3
如果您不能修改 A
的定义,那么,正如您已经发现的那样,您可以将其包装到您自己的定义中。
type MyA[P any] interface {
A
*P
}
func Handler[P any, T MyA[P]](callback func(result T)) {
result := new(P)
callback(result)
}
Handler(func(a *Aimpl) { fmt.Printf("%#v\n", a) })
一般来说,当你把约束写成P any, T MyA[P]
时,没有信息表明P
实现了某个接口。事实上 P
字面意思是 anything 因为你用 any
限制了它。 T
然后用 P
实例化并生成有效的实现程序这一事实与 P
本身无关。对于编译器,没有迹象表明 *P
(指向任何类型的指针)实现了 A
.
如果您想在回调签名中保留 A
的同时完成这项工作,请使用转换。您仍然需要捕获基类型才能传递 non-nil 指针实现程序,因此您将接口与指针约束 *T
包装在一起的方法原则上是正确的。
以后使用未命名的约束接口。类型参数的名称也是倒置的——T
是基本类型,P
是指针类型(逻辑上...):
func (a *Aimpl) SomeMethod() { fmt.Printf("called, %T, %t\n", a, a == nil) }
func Handler[P interface { *T; A }, T any](callback func(A)) {
p := P(new(T))
callback(p)
}
然后你需要用 *Aimpl
:
显式实例化 Handler
func main() {
Handler[*Aimpl](func(result A) { result.SomeMethod() })
// prints: called, *main.Aimpl, false
}
游乐场:https://go.dev/play/p/96_UFVnfyO-
更改回调类型的另一个选项允许您使用类型推断而不是显式实例化,因为这样您就已经知道实现者了。但目前尚不清楚 A
如何适合图片:
func main() {
// using the concrete type instead of A
Handler(func(result *Aimpl) { result.SomeMethod() })
}
我有这样的界面
type A interface {
SomeMethod()
}
我通过结构指针实现了这个接口:
type Aimpl struct {}
func (a *Aimpl) SomeMethod() {}
我有一个通用函数,它接受一个带有 A 参数的函数,如下所示:
func Handler[T A](callback func(result T)) {
// Essentially what I'd like to do is result := &Aimpl{} (or whatever T is)
callback(result)
}
我还应该补充一点,我不能修改 A
的定义(它来自图书馆)。我试过这个:
type MyA[T any] interface{
A
*T
}
但是这段代码给我一个错误:
func Handler[P any, T MyA[P]](callback func(result A)) {
result := new(P)
callback(result) // result does not implement interface. It's a pointer to a type, not a type
}
您可以使用类型参数声明接口,使其要求实现它的类型是指向其类型参数的指针。
type A[P any] interface {
SomeMethod()
*P
}
因此,您还需要稍微修改处理程序的签名。
func Handler[P any, T A[P]](callback func(result T)) {
result := new(P)
callback(result)
}
Handler(func(a *Aimpl) { fmt.Printf("%#v\n", a) })
https://go.dev/play/p/PY5iE7WoHt3
如果您不能修改 A
的定义,那么,正如您已经发现的那样,您可以将其包装到您自己的定义中。
type MyA[P any] interface {
A
*P
}
func Handler[P any, T MyA[P]](callback func(result T)) {
result := new(P)
callback(result)
}
Handler(func(a *Aimpl) { fmt.Printf("%#v\n", a) })
一般来说,当你把约束写成P any, T MyA[P]
时,没有信息表明P
实现了某个接口。事实上 P
字面意思是 anything 因为你用 any
限制了它。 T
然后用 P
实例化并生成有效的实现程序这一事实与 P
本身无关。对于编译器,没有迹象表明 *P
(指向任何类型的指针)实现了 A
.
如果您想在回调签名中保留 A
的同时完成这项工作,请使用转换。您仍然需要捕获基类型才能传递 non-nil 指针实现程序,因此您将接口与指针约束 *T
包装在一起的方法原则上是正确的。
以后使用未命名的约束接口。类型参数的名称也是倒置的——T
是基本类型,P
是指针类型(逻辑上...):
func (a *Aimpl) SomeMethod() { fmt.Printf("called, %T, %t\n", a, a == nil) }
func Handler[P interface { *T; A }, T any](callback func(A)) {
p := P(new(T))
callback(p)
}
然后你需要用 *Aimpl
:
Handler
func main() {
Handler[*Aimpl](func(result A) { result.SomeMethod() })
// prints: called, *main.Aimpl, false
}
游乐场:https://go.dev/play/p/96_UFVnfyO-
更改回调类型的另一个选项允许您使用类型推断而不是显式实例化,因为这样您就已经知道实现者了。但目前尚不清楚 A
如何适合图片:
func main() {
// using the concrete type instead of A
Handler(func(result *Aimpl) { result.SomeMethod() })
}