Golang中泛型方法的使用探讨
Golang中泛型方法的使用探讨 假设我想在 Go 1.18beta1 中为泛型切片实现一个 “map” 函数… 方法的原型应该类似于:
func (xs List[T]) Map(fct func(x T) S) List[S] {...}
假设 List[T] 定义为:
type List[T any] []T
遗憾的是,我还没有找到如何在方法声明中引入 S 泛型参数。这甚至可能实现吗?
6 回复
我同意,嵌套函数比链式函数更难阅读,但另一方面,使用自定义泛型切片类型的代码(通常)也比使用标准切片的代码更难阅读。
是的,我会这么做的……我原本更倾向于使用点号表示法来简化调用链,不过没关系……
我觉得 xs.map(fct).filter(pred) 比 filter(map(xs, fct), pred) 更清晰……但我也可以接受……
我不太熟悉 Go 语言中的泛型,但在 Reddit 上到处都能看到关于想要一个 Map 函数的这个具体问题,据我理解,你无法做到这一点,因为只有顶层函数才能拥有多个泛型参数。
如果你放弃定义自定义切片类型的要求,map 函数可以很好地工作:
func Map[T, S any](t []T, fct func(x T) S) []S {
var s []S
for _, x := range t {
s = append(s, fct(x))
}
return s
}
func main() {
t := []int{1, 2, 3}
s := Map(t, func(n int) int64 {
return int64(n)
})
fmt.Println(s)
}
关键在于,内置的切片类型已经是泛型的了,因此自定义的泛型切片类型可能并非必需(除非出于某些其他原因需要它)。
在 Go 1.18 及更高版本中,确实可以在方法上声明额外的类型参数。你需要将类型参数 S 放在方法名之后的方括号中。以下是实现示例:
package main
import "fmt"
type List[T any] []T
// Map 方法在方法名后声明了额外的类型参数 S
func (xs List[T]) Map[S any](f func(T) S) List[S] {
result := make(List[S], len(xs))
for i, x := range xs {
result[i] = f(x)
}
return result
}
func main() {
intList := List[int]{1, 2, 3, 4, 5}
// 将 int 转换为 string
strList := intList.Map(func(x int) string {
return fmt.Sprintf("Number: %d", x)
})
fmt.Println(strList) // [Number: 1 Number: 2 Number: 3 Number: 4 Number: 5]
// 将 int 转换为 float64
floatList := intList.Map(func(x int) float64 {
return float64(x) * 1.5
})
fmt.Println(floatList) // [1.5 3 4.5 6 7.5]
}
关键点:
- 方法类型参数
[S any]紧接在方法名Map之后 - 返回类型
List[S]使用了新引入的类型参数 - 转换函数
func(T) S的签名与类型参数匹配
这种方法声明完全符合 Go 泛型规范,允许在方法上定义独立的类型参数,提供了灵活的类型转换能力。

