当前位置: 首页 > news >正文

GO - 泛型编程

go - 泛型编程

介绍

泛型即开发过程中编写适用于所有类型的模板,只有在具体使用的时候才能确定其真正的类型。随着Go 1.18版本的发布,泛型正式成为了Go语言的一部分。
在编写代码时,我们经常会遇到需要处理不同类型的数据的情况。传统上,我们需要为每种类型编写不同的函数或数据结构,这导致了代码的重复和冗余。而泛型编程可以解决这个问题,使得我们可以编写通用的代码,适用于多种类型的数据。

泛型作用

泛型编程有许多优势,包括提高代码的可读性、可维护性和可扩展性,减少代码的重复和冗余,以及增加代码的灵活性。然而,泛型编程也有一些局限性,包括可能引入额外的复杂性,增加编译时间,以及不适用于所有情况。

golang的泛型怎么使用

泛型函数

泛型函数是可以接受不同类型参数的函数。在定义泛型函数时,我们使用类型参数来代表参数类型,从而实现函数的通用性。
使用:在 Go 语言中,我们使用 func 关键字来定义函数,泛型函数的定义与普通函数类似,只是在函数名后面添加了类型参数的声明。泛型函数的类型参数可以是任意类型,通常使用大写字母开头的单个字母来表示。
特化:当我们调用泛型函数时,编译器会根据传入参数的类型特化生成相应的函数。例如,当我们将一个 []int 类型的切片传入 Print 函数时,编译器会生成一个专门用于处理 int 类型切片的函数;同样地,当传入一个 []string 类型的切片时,会生成一个专门用于处理 string 类型切片的函数。

package mainimport "fmt"func Print[T any](s []T) {for _, v := range s {fmt.Println(v)}
}func main() {s := []int{1, 2, 3, 4, 5}Print(s)s2 := []string{"hello", "world"}Print(s2)
}

泛型类型

泛型类型是一种可以适用于多种类型数据的数据结构或容器。与普通类型不同,泛型类型中的某些部分使用类型参数来代表任意类型的数据。通过使用类型参数,我们可以定义一次通用的数据结构或容器,而不必针对每种类型都编写单独的实现。
使用:在 Go 语言中,泛型类型通常通过在类型名称后面添加类型参数列表来定义。类型参数列表使用方括号括起来,并在其中声明一个或多个类型参数。

type Stack[T any] struct {elements []T
}

Stack 是一个泛型类型,它接受一个类型参数 T,表示栈中存储的元素类型。通过使用类型参数 T,我们可以定义一个通用的栈数据结构,使得栈可以存储任意类型的元素。
泛型类型的定义之后,我们可以使用具体的类型来实例化泛型类型。例如,我们可以使用 Stack[int] 来表示一个整数类型的栈,使用 Stack[string] 来表示一个字符串类型的栈,以此类推。

stack := Stack[int]{}
package mainimport "fmt"type Stack[T any] struct {elements []T
}func (s *Stack[T]) Push(e T) {s.elements = append(s.elements, e)
}func (s *Stack[T]) Pop() T {if len(s.elements) == 0 {return nil}e := s.elements[len(s.elements)-1]s.elements = s.elements[:len(s.elements)-1]return e
}func main() {stack := Stack[int]{}stack.Push(1)stack.Push(2)stack.Push(3)fmt.Println(stack.Pop()) // Output: 3fmt.Println(stack.Pop()) // Output: 2fmt.Println(stack.Pop()) // Output: 1
}

泛型接口

泛型接口是一种可以接受任意类型参数的接口,它们使用类型参数来代表任意类型的数据。通过使用类型参数,我们可以定义一次通用的接口,而不必针对每种类型都编写单独的接口。这样,我们就能够针对不同类型的数据实现相同的接口方法,实现了对不同类型数据的通用操作。
使用 :泛型接口通常通过在接口名称后面添加类型参数列表来定义。类型参数列表使用方括号括起来,并在其中声明一个或多个类型参数。

type Container[T any] interface {Add(T)Remove() T
}

Container 是一个泛型接口,它接受一个类型参数 T,表示容器中存储的元素类型。通过使用类型参数 T,我们可以定义一个通用的容器接口,使得容器可以存储任意类型的元素,并且具有相同的添加和移除元素的方法。
泛型接口的定义之后,我们可以使用具体的类型来实现泛型接口。例如,我们可以针对不同类型的数据分别实现 Container 接口的方法:

type Queue[T any] struct {elements []T
}func (q *Queue[T]) Add(e T) {q.elements = append(q.elements, e)
}func (q *Queue[T]) Remove() T {if len(q.elements) == 0 {return nil}e := q.elements[0]q.elements = q.elements[1:]return e
}

我们针对不同类型的数据实现了 Container 接口的方法,分别用于实现一个泛型队列数据结构。通过实现泛型接口,我们可以实现对不同类型数据的通用操作,提高了代码的复用性和灵活性。

泛型结构体

泛型结构体是一种可以适用于多种类型数据的结构体,它们使用类型参数来代表任意类型的数据。通过使用类型参数,我们可以定义一次通用的结构体,而不必针对每种类型都编写单独的结构体。这样,我们就能够定义一个通用的数据结构,用于存储任意类型的数据。
使用:泛型结构体通常通过在结构体名称后面添加类型参数列表来定义。类型参数列表使用方括号括起来,并在其中声明一个或多个类型参数。例如:

type Pair[T any] struct {First  TSecond T
}

Pair 是一个泛型结构体,它接受一个类型参数 T,表示结构体中存储的元素类型。通过使用类型参数 T,我们可以定义一个通用的结构体,使得结构体中的字段可以存储任意类型的数据,并且具有相同的结构。
泛型结构体的定义之后,我们可以使用具体的类型来实例化泛型结构体。例如:

pair1 := Pair[int]{First: 1, Second: 2}
pair2 := Pair[string]{First: "hello", Second: "world"}

在上面的示例中,我们分别使用 Pair[int] 和 Pair[string] 来实例化了两个不同类型的泛型结构体。通过实例化泛型结构体,我们可以创建不同类型的数据结构,用于存储不同类型的数据。

泛型receiver

泛型 receiver 是指在方法定义中使用类型参数来表示接收者类型的一种方式。通过使用类型参数,可以使得方法适用于多种类型的接收者,从而实现对不同类型的数据的通用操作。
使用:在 Go 语言中,可以在方法定义中使用类型参数来表示接收者类型。例如:

type Stack[T any] struct {elements []T
}func (s *Stack[T]) Push(e T) {s.elements = append(s.elements, e)
}func (s *Stack[T]) Pop() T {if len(s.elements) == 0 {return nil}e := s.elements[len(s.elements)-1]s.elements = s.elements[:len(s.elements)-1]return e
}

Stack 结构体定义了一个泛型的栈数据结构,然后在方法定义中使用类型参数 T 来表示接收者类型。这样,Push 和 Pop 方法就可以适用于不同类型的栈,而不必针对每种类型都编写单独的方法。
下面是一个使用泛型 receiver 的示例,用于实现一个泛型栈数据结构:

package mainimport "fmt"type Stack[T any] struct {elements []T
}func (s *Stack[T]) Push(e T) {s.elements = append(s.elements, e)
}func (s *Stack[T]) Pop() T {if len(s.elements) == 0 {return nil}e := s.elements[len(s.elements)-1]s.elements = s.elements[:len(s.elements)-1]return e
}func main() {stack := Stack[int]{}stack.Push(1)stack.Push(2)stack.Push(3)fmt.Println(stack.Pop()) // Output: 3fmt.Println(stack.Pop()) // Output: 2fmt.Println(stack.Pop()) // Output: 1
}

泛型限制

匿名结构体与匿名函数不支持泛型

目前在 Go 语言中,匿名结构体和匿名函数不支持泛型。这意味着无法在匿名结构体或匿名函数中使用类型参数。

不支持类型断言

类型断言是一种在 Go 中用于判断接口值的实际类型的机制。然而,目前的泛型实现不支持类型断言。因此,在泛型代码中无法使用类型断言来判断类型。

不支持泛型方法,只能通过receiver来实现方法的泛型处理

目前,Go 语言的泛型实现中不支持直接在方法中使用类型参数。虽然可以通过在方法定义中使用类型参数来表示接收者类型(即泛型 receiver),但是不能直接在方法体内部使用类型参数。

~后的类型必须为基本类型,不能为接口类型

在使用泛型类型参数时,其类型必须为基本类型,不能为接口类型。这意味着类型参数不能用于定义接口类型,而只能用于定义基本类型的变量或参数。

http://www.lryc.cn/news/334489.html

相关文章:

  • TouchableOpacity和TouchableWithoutFeedback区别
  • MySQL EXISTS 语句和IN语句有啥区别
  • Java集合体系面试题
  • React-2-useState-获取DOM-组件通信
  • 使用nodejs搭建脚手架工具并发布到npm中
  • 【面经】3月29日 美团/美团平台/后端/一面/1h
  • CSS:CSS的基础了解
  • Android Framework学习笔记(2)----系统启动
  • 项目管理中的估算活动资源
  • java中的set集合及其子类
  • shell脚本查询匹配文件进行操作
  • vulnhub----natraj靶机
  • Web Component 组件库有什么优势
  • 如何配置vite的proxy
  • Linux CentOS基础操作
  • 最佳情侣身高差
  • 谷歌开发者账号防关联:如何选择性价比高的VPS,阿里、腾讯、酷鸟、AWS?
  • Virtual digital asset $E=$eaco. EarthChain
  • [计算机网络] 当输入网址到网页
  • 五年经验,还不懂小表驱动大表
  • springboot+websocket+微信小程序实现评论区功能
  • 【项目】如何在面试中介绍自己的项目经验(附如何解决未知的问题成长路线)
  • 解决Selenium元素拖拽不生效Bug
  • 提示工程中的10个设计模式
  • 提高网站安全性,漏洞扫描能带来什么帮助
  • 不要再使用 @Builder 注解了!有深坑呀!
  • 《UE5_C++多人TPS完整教程》学习笔记31 ——《P32 角色移动(Character Movement)》
  • 怎么使用jwt,token以及redis进行续期?
  • AI日报:北大Open Sora视频生成更强了;文心一言可以定制你自己的声音;天工 SkyMusic即将免费开放;
  • 替换空格(替换特定字符)