golang中的泛型概念以及使用:
由于go语言是强类型语言,所以在1.18版本以前,无法像使用PHP一样,随意对不同类型数据进行操作;为了解决这个问题在1.18版本以后就有了泛型的使用 所谓泛型就是:定义一类通用的模板变量,可以传入不同类型的变量,使得逻辑更加通用,代码更加精简。 注意:使用1.18版本,必须要对编辑(GOLAND)进行升级(现在GOLAND和go语言版本不知道是不是做了绑定,要使用高版本的go,必须升级GOLAND,然后面临收费问题),我用的是2021.1.3,最好2022版本,但是由于无法破解,所以一直用的2021版本,意味着无法使用泛型操作,但是可以在这个网站 https://gotipplay.golang.org 在线操作,建议在谷歌浏览器下执行,其它浏览器可能没有反应
我们可以这样定义一个泛型变量,比如,我们定义一个泛型切片,切片里的值类型,既可以是int,也可以是float64,也可以是string: type ScoreSlice [T int|float64|string] []T
这个怎么理解呢:
①T表示我们提炼出来的通用类型参数(Type parameter),是我们就用来表示不同类型的模板,T只是取的一个通用的名字,你可以取名任意其他名字都行。
②后面的int|float64|string 叫类型约束(Type constraint),也就是约束了T的取值范围,只能从(int、float64、string)中取值。中间的|表示的是或的关系,等于语法"||",所以你可以根据你类型的使用场景定义更多的类型约束。
③[]里面的这一串T int|float64|string,叫类型参数列表(type parameter list),表示的是我们定义了几个泛型的参数。我们例子当中只有1个,下面的例子中,我们会创建多个。
④最后面的[]T这个我们就很熟悉了,就是申请一个切片类型,比如常见的:[]int, []string 等等,只不过我们这里的类型是T,也就是参数列表里面定义的变量值。
这个 ScoreSlice 类型的切片相当于定义了三种类型的切片: []int []float64 []string
//来个官方的demo:
package main
import (
"fmt"
)
// This playground uses a development build of Go:
// devel go1.20-7c3284401f Thu Sep 15 06:23:50 2022 +0000
func Print[T any](s ...T) {
for _, v := range s {
fmt.Print(v)
}
}
func main() {
Print("Hello, ", "playground\n")
}
//定义泛型的Map,然后实例化对象
package main
import "fmt"
type MapA[K string, V any] map[K]V
func main() {
m1 := MapA[string, int]{"zhangsan": 16}
m1["zhangsan"] += 2 //修改val
m2 := MapA[string, string]{"lisi": "湖北省武汉市"}
fmt.Println(m1, m2)
}
注意如果写成下面的格式就会报错
package main
import "fmt"
type MapA[K string, V any] map[K]V
func main() {
m1 := MapA{"zhangsan": 16} //必须为 MapA[string, int]
m1["zhangsan"] += 2 //修改val
m2 := MapA{"lisi": "湖北省武汉市"} //MapA[string, int]
fmt.Println(m1, m2)
}
./prog.go:8:8: cannot use generic type MapA[K string, V any] without instantiation(实例化)
./prog.go:11:8: cannot use generic type MapA[K string, V any] without instantiation实例化)
//定义泛型的Channel,然后实例化对象
package main
import "fmt"
type C[T int|float64] chan T
func main() {
cha := make(C[int], 1)
cha <- 1
fmt.Println(<-cha)
chb := make(C[float64], 1)
chb <- 23.56
fmt.Println(<-chb)
}
//定义泛型的Slice,然后实例化对象,最后调用泛型函数打印输出
package main
import "fmt"
type SliceT[T any] []T
func testSlice[T any](s []T) { //[T any]表示支持任何类型的参数 (s []T表示形参s是一个T类型的切片)
for _, v := range s {
fmt.Println("val is:", v)
}
}
func main() {
s1 := SliceT[int]{1,3,5,7}
testSlice(s1)
s2 := SliceT[string]{"zhangsan","lisi","wangwu"}
testSlice(s2)
}
//使用interface中规定的类型 约束泛型函数的参数
package main
import "fmt"
type NumStr interface {
int | int32 | string //这个在高版本的golang下才会生效,如果换成自定义的 struct,好像不太能操作
}
func add[T NumStr](a, b T) T {
return a + b
}
func main() {
fmt.Println(add(-3,-4))
fmt.Println(add(10.34,23.78))// 会报错:./prog.go:15:16: float64 does not implement NumStr (float64 missing in int | int32 | string)
fmt.Println(add("hello","world"))
}
//其实最想验证的是 泛型的 struct,不知道可不可以
package main
import "fmt"
type A struct {
name string
}
func GetVal[T A]() T {
return T{ // 这里如果写 A 会报:./prog.go:11:9: cannot use A{…} (value of type A) as type T in return statement
name: "zhangsan",
}
}
func main() {
fmt.Println(GetVal())
}
