指尖上的记忆指尖上的记忆
首页
  • 基础
  • Laravel框架
  • Symfony框架
  • 基础
  • Gin框架
  • 基础
  • Spring框架
  • 命令
  • Nginx
  • Ai
  • Deploy
  • Docker
  • K8s
  • Micro
  • RabbitMQ
  • Mysql
  • PostgreSsql
  • Redis
  • MongoDb
  • Html
  • Js
  • 前端
  • 后端
  • Git
  • 知识扫盲
  • Golang
🌟 gitHub
首页
  • 基础
  • Laravel框架
  • Symfony框架
  • 基础
  • Gin框架
  • 基础
  • Spring框架
  • 命令
  • Nginx
  • Ai
  • Deploy
  • Docker
  • K8s
  • Micro
  • RabbitMQ
  • Mysql
  • PostgreSsql
  • Redis
  • MongoDb
  • Html
  • Js
  • 前端
  • 后端
  • Git
  • 知识扫盲
  • Golang
🌟 gitHub

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())

}