GO基础进阶篇 (十三)、泛型

泛型

先看一下这段代码。

package main

import "fmt"

func main() {
   
	strs := []string{
   "a", "b"}
	printArray(strs)
}

func printArray(arr []interface{
   }) {
   
	for _, a := range arr {
   
		fmt.Println(a)
	}
}

上面的代码中,我们想要打印参数arr的信息。运行报错

 cannot use strs (variable of type []string) as []interface{
   } value in argument to printArray

想要解决的话,按照之前我们的学习,可以将函数改编如下(使用断言)

package main

import "fmt"

func main() {
   
	strs := []string{
   "a", "b"}
	printStringArray(strs)
}

func printStringArray(arr interface{
   }) {
   
	for _, a := range arr.([]string) {
   
		fmt.Println(a)
	}
}

但这样会有一个坏处,当我们想要打印另一个非string的数组时,就不得不再写一个方法

package main

import "fmt"

func main() {
   
	ints := []int{
   1, 2}
	printIntArray(ints)
}

func printIntArray(arr interface{
   }) {
   
	for _, a := range arr.([]int) {
   
		fmt.Println(a)
	}
}

这样处理,就会导致有无限多相似的代码产生,这样的代码时不合格的。

此时,泛型就出现了。它的意义时不在方法定义时决定变量的类型,而让使用者使用时决定。

package main

import "fmt"

func main() {
   
	ints := []int{
   1, 2}
	strs := []string{
   "a", "b"}
	printArray(ints)
	printArray(strs)
}

func printArray[T string | int](arr []T) {
   
	for _, a := range arr {
   
		fmt.Println(a)
	}
}

T代表了用户传入的类型,并对T进行了约束。上面的代码中,我们再定一个float的数组,是无法通过程序校验的,因为我们约束了T的可用类型为stirng与int。

使用泛型,你可能会产生一个疑惑,通过我们刚刚学习的反射,再加上接口。也可以类似泛型这样的函数。这样是可行的,但反射的机制存在一些问题

  • 1.用起来麻烦
  • 2.失去了编译时的类型检查,容易出错
  • 3.性能不理想

结论:当需要因为不同类型写完全相同的逻辑代码时,使用泛型时最合适的选择。

泛型类型

  • 泛型切片
package main

import "fmt"

func main() {
   
	type Slice[T int | string | float32] []T
	var a Slice[int] = []int{
   1, 2, 3}
	var b Slice[string] = []string{
   "a", "b", "c"}
	var c Slice[float32] = []float32{
   1, 2, 3}

	fmt.Printf("%T", a)
	fmt.Println(a)
	fmt.Printf("%T", b)
	fmt.Println(b)
	fmt.Printf("%T", c)
	fmt.Println(c)
}

//main.Slice[int][1 2 3]
//main.Slice[string][a b c]
//main.Slice[float32][1 2 3]

  • 泛型map
package main

import "fmt"

func main() {
   
	type MyMap[KEY int | string, VALUE float32] map[KEY]VALUE

	var m1 MyMap[string, float32] = map[string]float32{
   
		"a": 1.1,
		"b": 1.2,
	}

	fmt.Println(m1)
}

  • 其他
	//泛型结构体
	type MyStruct[T int | string] struct {
   
		id   T
		Name stirng
	}
	//泛型接口
	type IPrintData[T int | float32 | string] interface {
   
	}
	//泛型通道
	type MyChan[T string | int] chan T

泛型函数与方法

package main

import "fmt"

func main() {
   
	//给泛型添加方法
	var s MySlice[int] = []int{
   1, 2, 3, 4}
	fmt.Println(s.Sum())

	var s1 MySlice[float64] = []float64{
   1.1, 2.1, 3.1, 4.1}
	fmt.Println(s1.Sum())

	//泛型函数
	fmt.Println(Add[int](1, 2))
	fmt.Println(Add[string]("1", "2"))

	//如果类型能被自动推断,函数调用时的T可以省略
	fmt.Println(Add(1, 2))
	fmt.Println(Add("1", "2"))
}

type MySlice[T int | string | float64] []T
func (s MySlice[T]) Sum() T {
   
	var sum T
	for _, v := range s {
   
		sum += v
	}
	return sum
}

func Add[T int | float32 | string](a T, b T) T {
   
	return a + b
}

实际开发中,泛型使用较多的场景就是泛型的函数与方法。

自定义泛型约束

package main

import "fmt"

func main() {
   
	fmt.Println(GetMaxNum(1, 2))
	fmt.Println(GetMaxNum(1.5, 2.6))
}

type MyInt interface {
   
	int | int8 | int16 | int32 | float64
}

func GetMaxNum[T MyInt](a, b T) T {
   
	if a > b {
   
		return a
	}
	return b
}

相关推荐

  1. GO基础 ()、

    2024-01-18 06:56:05       52 阅读
  2. GO基础 (二)、反射

    2024-01-18 06:56:05       56 阅读
  3. GO基础 (八)、runtime包

    2024-01-18 06:56:05       65 阅读
  4. GO基础 (六)、I/O流

    2024-01-18 06:56:05       52 阅读

最近更新

  1. docker php8.1+nginx base 镜像 dockerfile 配置

    2024-01-18 06:56:05       94 阅读
  2. Could not load dynamic library ‘cudart64_100.dll‘

    2024-01-18 06:56:05       100 阅读
  3. 在Django里面运行非项目文件

    2024-01-18 06:56:05       82 阅读
  4. Python语言-面向对象

    2024-01-18 06:56:05       91 阅读

热门阅读

  1. 服务器租用和托管有哪些注意事项?

    2024-01-18 06:56:05       49 阅读
  2. 基于博弈树的开源五子棋AI教程[7 多线程搜索]

    2024-01-18 06:56:05       41 阅读
  3. npm换源

    npm换源

    2024-01-18 06:56:05      52 阅读
  4. 【Spring Boot 3】【Redis】集成Jedis

    2024-01-18 06:56:05       44 阅读
  5. npm-yarn

    2024-01-18 06:56:05       56 阅读
  6. 国内环境 GitHub 拉取仓库速度慢的缓解方案

    2024-01-18 06:56:05       59 阅读