我剛剛看到 Go 在其最新版本中加入了泛型,我正在嘗試創建一個小專案來了解它是如何作業的。除了現在通用的非常簡單的功能之外,我似乎不知道它是如何作業的。我希望能夠做這樣的事情:
type Dao[RT any] interface {
FindOne(id string) *RT
}
type MyDao struct {
}
type ReturnType struct {
id int
}
func (m *MyDao) FindOne(id string) *ReturnType {
panic("implement me")
}
// how should this look like?
func NewMyDao() *Dao[ReturnType] {
return &MyDao[ReturnType]{}
}
這甚至可能嗎?我似乎沒有以這種方式實作介面,并且我嘗試了許多相同的組合。
有沒有辦法實作通用介面?如果不是,是否只能回傳interface{}
型別?
uj5u.com熱心網友回復:
該型別*MyDao
實作了介面Dao[ReturnType]
。因此,該函式應如下所示:
func NewMyDao() Dao[ReturnType] {
return &MyDao{}
}
請注意,回傳型別是泛型介面的一個實體,回傳值只是該*MyDao
型別的一個實體。
uj5u.com熱心網友回復:
型別實際上并不實作泛型介面,它們實作泛型介面的實體化。沒有實體化就不能使用泛型型別(包括介面)。從那里開始,它就像預泛型 Go 一樣,包括帶有指標接收器的方法之間的區別。
因此,如果你用具體型別重寫它們,想想使用型別引數的方法會是什么樣子是有幫助的。
讓我們考慮一個通用介面和某種型別:
type Getter[T any] interface {
Get() T
}
type MyStruct struct {
Val string
}
有幾種可能的情況
具有具體型別引數的介面
實體化為Getter[string]
,由帶方法的型別實作Get() string
// implements Getter[string]
func (m MyStruct) Get() string {
return m.Val
}
// ok
func foo() Getter[string] {
return MyStruct{}
}
以型別引數作為型別引數的介面
具有型別引數的函式可以使用它們來實體化泛型型別,例如Getter[T]
. 實作者必須有確切的Get() T
方法。為了使其有效,它們也是通用的并使用相同的型別引數進行實體化:
所以這不會編譯,即使T
是string
// Getter[T] literally needs implementors with `Get() T` method
func bar[T any]() Getter[T] {
return MyStruct{} // doesn't compile, even if T is string
}
制作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]{} // ok
}
具有通用實作器的具體介面
讓我們扭轉以前的情況。我們保持引數化MyStruct[T any]
,但現在介面沒有引數化:
type Getter interface {
Get() string
}
在這種情況下,僅在使用必要的具體型別實體化時才MyStruct
實作:Getter
// Getter requires method `Get() string`
func baz() Getter {
return MyStruct[string]{} // instantiate with string, ok
// return MyStruct[int]{} // instantiate with something else, doesn't compile
}
指標接收器
這遵循與上述相同的規則,但需要像往常一樣實體化指標型別:
// pointer receiver, implements Getter[string]
func (m *MyStruct) Get() string {
return m.Val
}
func foo() Getter[string] {
return &MyStruct{} // ok
// return MyStruct{} // doesn't implement
}
如果MyStruct
是通用的,它也是一樣的。
// parametrized pointer receiver
func (m *MyStruct[T]) Get() T {
return m.Val
}
func foo() Getter[string] {
return &MyStruct[string]{} // ok
}
所以在你的情況下,用具體型別替換型別引數的心理練習給出了Dao[ReturnType]
方法FindOne(id string) *ReturnType
。實作此方法的型別是*MyDao
(指標接收器),因此:
func NewMyDao() Dao[ReturnType] {
return &MyDao{}
}
轉載請註明出處,本文鏈接:https://www.uj5u.com/yidong/470427.html