今年开始,来自golang团队的新消息,"增加泛型!"。
如果你熟悉Java或C#等语言,你已经熟悉了泛型的概念。例如,让我们来谈谈数组的排序问题:
package main
import (
"fmt"
"sort"
)
func main() {
f := func(msg string, v []int) {
fmt.Println(msg)
for _, x := range v {
fmt.Printf("%d ", x)
}
fmt.Println()
}
v := []int{10, 20, 100, 2, -1, 80}
f("before sort", v)
sort.Ints(v)
f("after sort", v)
}
在上面的代码中,我们只是使用了sort 包来对一个整数片进行排序并打印出来。
一切看起来都很好,对吗?那么,如果我们想对其他数字类型的片断进行排序呢?sort 包有另一个名为Float64s 的函数(而不是Ints ),但这肯定是不够的,因为我们可能需要对其他数字类型做一些排序操作,比如int32 。
因此,一种方法是为每个数字类型定义一个函数,但我们都知道这不是最好的主意!这就是Generic 的地方。
以下是维基百科中对泛型的定义:
泛型编程是计算机编程的一种风格,在这种风格中,算法是以以后要指定的类型来编写的,然后在需要时对作为参数提供的特定类型进行实例化。
因此,泛型的要点是,以后指定变量的类型并将其作为参数提供。这正是我们所需要的,例如在我们的排序函数中。我们唯一需要的是确保我们的输入符合我们的条件。例如,在排序的情况下,它必须是numeric 。
让我们看看如何在golang中使用泛型:
func Bored[T any](s ...T) T {
return s[0]
}
Bored 函数给出一个 的片断作为输入,并返回该片断中的第一个项目作为输出。那么WTH是 ?首先,让我们看看如何使用我们的 函数。T T Bored
func main() {
output := Bored("Hello", "Generics")
fmt.Println(output)
}
很好,通用函数的使用和普通函数完全一样!所以我们来谈谈T 。在这种情况下,T 就是string 。那么通用函数和老式的去interface{} 有什么区别呢?我将用一个例子来解释它:
func Bored(s ...interface{}) interface{} {
return "I am string"
}
func main() {
output := Bored(1,1.1,"hello", struct{}{})
fmt.Println(output)
}
区别在于,interface{} 可以是任何东西,但在第一个函数中,T 的类型是在传递第一个元素时确定的。如果它是一个字符串,其余的也必须是一个字符串。否则,在编译应用程序时你会得到一个错误:
func Bored[T any](s ...T) T {
return s[0]
}
func main() {
output := Bored("Hello", "Generics", 1)
fmt.Println(output)
}
输出:
type checking failed for main
prog.go2:11:39: default type int of 1 does not match inferred type string for T
这很好,不是吗?对于Java或C#开发人员来说,像Repository<T> 这样的东西是非常熟悉的,其中T 几乎总是应用程序的实体之一。
回到Golang ,现在引入的另一种类型(而不是any )是comparable 。这意味着该项目必须有能力进入equality operation :
package main
import (
"fmt"
)
func main() {
fmt.Println(Equal(1, 1)) // true
fmt.Println(Equal(2, 1)) // false
}
func Equal[T comparable] (input1, input2 T) bool {
return input1 == input2
}
和前面的例子一样,如果向这个函数传递多个数据类型,我们会得到一个编译时间:
func main() {
fmt.Println(Equal(1.1, 1))
}
/*
output: type checking failed for main
prog.go2:8:25: default type int of 1 does not match inferred type float64 for T
*/
我认为golang团队为开发者提供了一些方法来定义T 。目前,我只看到了any 和comparable ,如果你知道更多的类型化参数,请在评论区分享它们。