同时具有接口和实现的 Golang 泛型
Golang generics with interface and implementation at same time
我正在尝试编写以下函数:
func Fill[X any](slice []*X){
for i := range slice {
slice[i] = new(X)
}
}
xs := make([]*int, 10) // fill with nils
Fill(xs) // now fill with new(int)
这很好用,但是……如果我想使用一部分接口并提供具体类型?
func Fill[X, Y any](slice []X){
for i := range slice {
slice[i] = new(Y) // not work!
}
}
xs := make([]sync.Locker, 10) // fill with nils
Fill[sync.Locker,sync.Mutex](xs) // ouch
我尝试了一些组合都没有成功,有什么办法还是go1.18不支持这样的关系?
当您将 X
和 Y
都约束为 any
时,您将失去所有 interface-implementor 关系。编译时唯一知道的是 X
和 Y
是不同的类型,你不能在函数体内将一个赋值给另一个。
使其编译的一种方法是使用显式断言:
func Fill[X, Y any](slice []X) {
for i := range slice {
slice[i] = any(*new(Y)).(X)
}
}
但是如果 Y
没有真正实现 X
, 就像你的情况一样,这会引起恐慌,因为实现 sync.Locker
.
的是 *sync.Mutex
(指针类型)
此外,当 Y
用指针类型实例化时,您会丢失有关基类型的信息,因此零值,包括 *new(Y)
将是 nil
,因此您与 make
相比并没有真正的基线改进(只是键入 nils 与 nil 接口)。
你 会 想做的是将 Y
限制为 X
,就像 Fill[X any, Y X](slice []X)
一样,但这是不可能的,因为 1)类型参数不能用作约束; and/or 2) 约束不能直接嵌入类型参数。它还会像上面那样初始化 nils。
更好的解决方案是使用构造函数而不是第二个类型参数:
func main() {
xs := make([]sync.Locker, 10)
Fill(xs, func() sync.Locker { return &sync.Mutex{} })
}
func Fill[X any](slice []X, f func() X) {
for i := range slice {
slice[i] = f()
}
}
我正在尝试编写以下函数:
func Fill[X any](slice []*X){
for i := range slice {
slice[i] = new(X)
}
}
xs := make([]*int, 10) // fill with nils
Fill(xs) // now fill with new(int)
这很好用,但是……如果我想使用一部分接口并提供具体类型?
func Fill[X, Y any](slice []X){
for i := range slice {
slice[i] = new(Y) // not work!
}
}
xs := make([]sync.Locker, 10) // fill with nils
Fill[sync.Locker,sync.Mutex](xs) // ouch
我尝试了一些组合都没有成功,有什么办法还是go1.18不支持这样的关系?
当您将 X
和 Y
都约束为 any
时,您将失去所有 interface-implementor 关系。编译时唯一知道的是 X
和 Y
是不同的类型,你不能在函数体内将一个赋值给另一个。
使其编译的一种方法是使用显式断言:
func Fill[X, Y any](slice []X) {
for i := range slice {
slice[i] = any(*new(Y)).(X)
}
}
但是如果 Y
没有真正实现 X
, 就像你的情况一样,这会引起恐慌,因为实现 sync.Locker
.
*sync.Mutex
(指针类型)
此外,当 Y
用指针类型实例化时,您会丢失有关基类型的信息,因此零值,包括 *new(Y)
将是 nil
,因此您与 make
相比并没有真正的基线改进(只是键入 nils 与 nil 接口)。
你 会 想做的是将 Y
限制为 X
,就像 Fill[X any, Y X](slice []X)
一样,但这是不可能的,因为 1)类型参数不能用作约束; and/or 2) 约束不能直接嵌入类型参数。它还会像上面那样初始化 nils。
更好的解决方案是使用构造函数而不是第二个类型参数:
func main() {
xs := make([]sync.Locker, 10)
Fill(xs, func() sync.Locker { return &sync.Mutex{} })
}
func Fill[X any](slice []X, f func() X) {
for i := range slice {
slice[i] = f()
}
}