类型实际上不会实现通用接口,它们实现通用接口的实例化。 您无法使用未实例化的通用类型(包括接口)。从那里开始,就像在没有泛型的 Go 中一样,包括具有指针接收器的方法之间的区别。
因此,如果您使用具体类型重写使用类型参数的方法,则会非常有帮助。
让我们考虑一个通用接口和一些类型:
type Getter[T any] interface {
Get() T
}
type MyStruct struct {
Val string
}
有几种可能的情况
具体类型参数接口
实例化为Getter[string]
,由具有Get() string
方法的类型实现
func (m MyStruct) Get() string {
return m.Val
}
func foo() Getter[string] {
return MyStruct{}
}
带有类型参数的接口作为类型参数
具有类型参数的函数可以使用它们来实例化通用类型,例如Getter[T]
。 实现者必须具有完全相同的Get() T
方法。 为了使其有效,它们也必须是通用的,并使用相同的类型参数进行实例化:
因此,即使T
是string
,这也不会编译。
func bar[T any]() Getter[T] {
return MyStruct{}
}
使
MyStruct
也成为参数化的工作:
type MyStruct[T any] struct {
Val T
}
func (m MyStruct[T]) Get() T {
return m.Val
}
func bar[T any]() Getter[T] {
return MyStruct[T]{}
}
具有通用实现的具体接口
让我们反转之前的情况。我们保留参数化的MyStruct[T any]
,但现在接口不是参数化的:
type Getter interface {
Get() string
}
在这种情况下,只有当使用必要的具体类型实例化
MyStruct
时,它才实现了
Getter
。
func baz() Getter {
return MyStruct[string]{}
}
指针接收器
这遵循与上述相同的规则,但通常需要实例化指针类型:
func (m *MyStruct) Get() string {
return m.Val
}
func foo() Getter[string] {
return &MyStruct{}
}
如果MyStruct
是通用的,则情况相同。
func (m *MyStruct[T]) Get() T {
return m.Val
}
func foo() Getter[string] {
return &MyStruct[string]{}
}
在您的情况下,将类型参数替换为具体类型的思维练习使得Dao[ReturnType]
具有FindOne(id string) *ReturnType
方法。实现此方法的类型是*MyDao
(指针接收器),因此:
func NewMyDao() Dao[ReturnType] {
return &MyDao{}
}