(一) 示例1
- package _case
- import "fmt"
- // 定义用户类型的结构体
- type user struct {
- ID int64
- Name string
- Age uint8
- }
- // 定义地址类型的结构体
- type address struct {
- ID int
- Province string
- City string
- }
- // 集合转列表函数,接受一个 map,返回一个切片
- func mapToList[k comparable, T any](mp map[k]T) []T {
- // 创建切片,长度与 map 的长度相同
- list := make([]T, len(mp))
- var i int
- for _, data := range mp {
- list[i] = data
- i++
- }
- return list
- }
- // 打印通道内容的函数,接受一个通道并打印通道中的每一个数据
- func myPrintln[T any](ch chan T) {
- for data := range ch {
- fmt.Println(data)
- }
- }
- // 主函数,执行类型转换和打印
- func TTypeCase() {
- // 创建一个用户类型的 map
- userMp := make(map[int64]user, 0)
- // 向 map 中添加用户数据
- userMp[1] = user{ID: 1, Name: "heheda", Age: 18}
- userMp[2] = user{ID: 2, Name: "Jerry", Age: 20}
- userMp[3] = user{ID: 3, Name: "Tom", Age: 22}
- // 将用户 map 转换为用户列表
- userList := mapToList[int64, user](userMp)
- // 创建用户类型的通道,并启动 goroutine 打印通道数据
- ch := make(chan user)
- go myPrintln(ch)
- // 将用户列表中的数据发送到通道
- for _, u := range userList {
- ch <- u
- }
- close(ch)
- // 创建一个地址类型的 map
- addrMp := make(map[int64]address, 0)
- // 向 map 中添加地址数据
- addrMp[1] = address{ID: 1, Province: "湖南", City: "长沙"}
- addrMp[2] = address{ID: 2, Province: "广东", City: "揭阳"}
- // 将地址 map 转换为地址列表
- addrList := mapToList[int64, address](addrMp)
- // 创建地址类型的通道,并启动 goroutine 打印通道数据
- ch1 := make(chan address)
- go myPrintln(ch1)
- // 将地址列表中的数据发送到通道
- for _, addr := range addrList {
- ch1 <- addr
- }
- close(ch1)
- }
- // 泛型切片的定义
- type List[T any] []T
- // 泛型 map 的定义
- // 声明两个泛型,分别为 k 、 v
- type MapT[k comparable, v any] map[k]v
- // 泛型通道的定义
- type Chan[T any] chan T
- func TTypeCase1() {
- // map[int64]user -> MapT[int64, user]
- userMp := make(MapT[int64, user], 0)
- userMp[1] = user{ID: 1, Name: "heheda", Age: 18}
- userMp[2] = user{ID: 2, Name: "Jerry", Age: 20}
- userMp[3] = user{ID: 3, Name: "Tom", Age: 22}
- var userList List[user]
- userList = mapToList[int64, user](userMp)
- ch := make(Chan[user])
- go myPrintln(ch)
- for _, u := range userList {
- ch <- u
- }
- close(ch)
- // map[int64]address -> MapT[int64, address]
- addrMp := make(MapT[int64, address], 0)
- addrMp[1] = address{ID: 1, Province: "湖南", City: "长沙"}
- addrMp[2] = address{ID: 2, Province: "广东", City: "揭阳"}
- var addrList List[address]
- addrList = mapToList[int64, address](addrMp)
- ch1 := make(Chan[address])
- go myPrintln(ch1)
- for _, addr := range addrList {
- ch1 <- addr
- }
- close(ch1)
- }
复制代码
这段代码展示了如何使用 Go 语言中的泛型、结构体和通道举行数据处理和打印。以下是对代码各部分的解释:
1.包和导入
- package _case
- import "fmt"
复制代码
2.结构体定义
- user 结构体 有三个字段:ID(范例 int64)、Name(范例 string)和 Age(范例 uint8)
- address 结构体 有三个字段:ID(范例 int)、Province(范例 string)和 City(范例 string)
3.泛型函数
- func mapToList[k comparable, T any](mp map[k]T) []T {
- list := make([]T, len(mp))
- var i int
- for _, data := range mp {
- list[i] = data
- i++
- }
- return list
- }
复制代码
- mapToList 是一个泛型函数,它担当一个 map 范例的参数 mp,并将其转换为切片(列表)
- 这里使用了两个泛型范例参数:k(可比较范例)和 T(恣意范例)
4.打印通道内容的泛型函数
- func myPrintln[T any](ch chan T) {
- for data := range ch {
- fmt.Println(data)
- }
- }
复制代码
- myPrintln 是一个泛型函数,担当一个通道范例的参数 ch,并打印通道中的每一个数据
5.主函数 TTypeCase
- func TTypeCase() {
- userMp := make(map[int64]user, 0)
- userMp[1] = user{ID: 1, Name: "heheda", Age: 18}
- userMp[2] = user{ID: 2, Name: "Jerry", Age: 20}
- userMp[3] = user{ID: 3, Name: "Tom", Age: 22}
- userList := mapToList[int64, user](userMp)
-
- ch := make(chan user)
- go myPrintln(ch)
- for _, u := range userList {
- ch <- u
- }
- close(ch)
-
- addrMp := make(map[int64]address, 0)
- addrMp[1] = address{ID: 1, Province: "湖南", City: "长沙"}
- addrMp[2] = address{ID: 2, Province: "广东", City: "揭阳"}
- addrList := mapToList[int64, address](addrMp)
-
- ch1 := make(chan address)
- go myPrintln(ch1)
- for _, addr := range addrList {
- ch1 <- addr
- }
- close(ch1)
- }
复制代码
- 这个函数首先创建两个 map 分别存储用户和地址数据
- 使用 mapToList 将 map 转换为列表(切片)
- 创建通道并启动 goroutine 打印通道数据
- 将列表中的数据写入通道并关闭通道
6.泛型范例
- 定义三个新的泛型范例:List、MapT 和 Chan
- type List[T any] []T
- type MapT[k comparable, v any] map[k]v
- type Chan[T any] chan T
复制代码 7.另一主函数 TTypeCase1
- func TTypeCase1() {
- // map[int64]user -> MapT[int64, user]
- userMp := make(MapT[int64, user], 0)
- userMp[1] = user{ID: 1, Name: "heheda", Age: 18}
- userMp[2] = user{ID: 2, Name: "Jerry", Age: 20}
- userMp[3] = user{ID: 3, Name: "Tom", Age: 22}
-
- var userList List[user]
- userList = mapToList[int64, user](userMp)
-
- ch := make(Chan[user])
- go myPrintln(ch)
- for _, u := range userList {
- ch <- u
- }
- close(ch)
-
- // map[int64]address -> MapT[int64, address]
- addrMp := make(MapT[int64, address], 0)
- addrMp[1] = address{ID: 1, Province: "湖南", City: "长沙"}
- addrMp[2] = address{ID: 2, Province: "广东", City: "揭阳"}
-
- var addrList List[address]
- addrList = mapToList[int64, address](addrMp)
-
- ch1 := make(Chan[address])
- go myPrintln(ch1)
- for _, addr := range addrList {
- ch1 <- addr
- }
- close(ch1)
- }
复制代码
- TTypeCase1 函数与 TTypeCase 类似,但使用了自定义的泛型范例 MapT 和 List
相关知识点
- 泛型 泛型允许函数和数据结构定义中使用范例参数,从而提拔代码的复用性
- 结构体 结构体是 Go 中用于将多个字段组合成一个单一范例的数据结构
- 通道(Channel)通道是在 goroutine 之间通报数据的管道,可以同步或者异步
- goroutine goroutine 是 Go 中轻量级的线程,用于并发编程
- map map 是一种内建的数据结构,用于存储键值对
可以实验运行和修改代码,进一步理解这些概念。
(二) 示例2
- package _case
- import "fmt"// 定义接口 ToString,有一个 String() 方法type ToString interface { String() string}// user 结构体实现 ToString 接口func (u user) String() string { return fmt.Sprintf("ID: %d,Name: %s,Age: %d", u.ID, u.Name, u.Age)}// address 结构体实现 ToString 接口func (addr address) String() string { return fmt.Sprintf("ID: %d,Province: %s,City: %s", addr.ID, addr.Province, addr.City)}// 定义泛型接口 GetKey,要求实现 Get() 方法返回范例 Ttype GetKey[T comparable] interface {
- any Get() T}// user 结构体实现 GetKey 接口,Get() 返回 IDfunc (u user) Get() int64 { return u.ID}// address 结构体实现 GetKey 接口,Get() 返回 IDfunc (addr address) Get() int { return addr.ID}// 泛型函数 listToMap,将列表转换为 mapfunc listToMap[k comparable, T GetKey[k]](list []T) map[k]T { mp := make(map[k]T, len(list)) // 创建 map,长度为列表长度 for _, data := range list { mp[data.Get()] = data // 使用 Get() 方法获取键 } return mp}// 主函数,演示列表转 map 的操纵func InterfaceCase() { // 创建 user 列表,元素实现了 GetKey[int64] 接口 userList := []GetKey[int64]{ user{ID: 1, Name: "张三", Age: 18}, user{ID: 2, Name: "李四", Age: 19}, } // 创建 address 列表,元素实现了 GetKey[int] 接口 addrList := []GetKey[int]{ address{ID: 1, Province: "广东", City: "揭阳"}, address{ID: 2, Province: "湖南", City: "长沙"}, } // 将 user 列表转换为 map,并打印效果 userMp := listToMap[int64, GetKey[int64]](userList) fmt.Println(userMp) // 将 address 列表转换为 map,并打印效果 addrMp := listToMap[int, GetKey[int]](addrList) fmt.Println(addrMp)}
复制代码
1.包和导入
- package _case
- import "fmt"
复制代码 导入 fmt 包用于格式化输入输出。
2.定义基本接口
- type ToString interface {
- String() string
- }
复制代码 3.实现 ToString 接口
- func (u user) String() string {
- return fmt.Sprintf("ID: %d,Name: %s,Age: %d", u.ID, u.Name, u.Age)
- }
- func (addr address) String() string {
- return fmt.Sprintf("ID: %d,Province: %s,City: %s", addr.ID, addr.Province, addr.City)
- }
复制代码
- user 和 address 结构体实现了 ToString 接口的 String 方法,返回结构体的字符串体现。
4.定义泛型接口
- type GetKey[T comparable] interface {
- any
- Get() T
- }
复制代码 这是一个泛型接口声明。具体来说,GetKey 接口担当一个范例参数 T,这个范例参数必须是一个可比较的范例 (comparable)
(1)定义泛型接口
- type GetKey[T comparable] interface {
复制代码
- GetKey 定义了一个泛型接口。
- T 是一个范例参数,它必须是一个可比较的范例 (comparable)。可比较范例体现可以使用 == 和 != 运算符举行比较,常见的可比较范例包括整数、浮点数、字符串以及指针等。
(2)嵌入 any 接口
- Go 1.18 引入了范例聚集 any,它是 interface{} 的别名,体现恣意范例
- 在接口中嵌入 any 意味着该接口可以担当任何范例的实现
(3)定义方法
- 定义了一个方法 Get,这个方法返回范例 T。
- 因为 T 是一个范例参数,所以 Get 方法的返回值范例是泛型的,可以是恣意 T 范例
5.实现 GetKey 接口
- func (u user) Get() int64 {
- return u.ID
- }
- func (addr address) Get() int {
- return addr.ID
- }
复制代码
- user 和 address 结构体实现了 GetKey 接口的 Get 方法,分别返回结构体的 ID 字段
- user 实现了 GetKey[int64] 接口,而 address 实现了 GetKey[int] 接口
6.列表转聚集函数
- func listToMap[k comparable, T GetKey[k]](list []T) map[k]T {
- mp := make(MapT[k, T], len(list))
- for _, data := range list {
- mp[data.Get()] = data
- }
- return mp
- }
复制代码
- listToMap 是一个泛型函数,将 list 转换为 map
- 函数参数 k 为键的范例,T 为实现 GetKey[k] 接口的范例
- data.Get() 返回键,作为 map 的键
7.主函数 InterfaceCase
- func InterfaceCase() {
- userList := []GetKey[int64]{
- user{ID: 1, Name: "张三", Age: 18},
- user{ID: 2, Name: "李四", Age: 19},
- }
- addrList := []GetKey[int]{
- address{ID: 1, Province: "广东", City: "揭阳"},
- address{ID: 2, Province: "湖南", City: "长沙"},
- }
- userMp := listToMap[int64, GetKey[int64]](userList)
- fmt.Println(userMp)
- addrMp := listToMap[int, GetKey[int]](addrList)
- fmt.Println(addrMp)
- }
复制代码
- 创建 userList 和 addrList,分别包罗 user 和 address 结构体
- 调用 listToMap 将列表转换为 map,并打印效果
>>分解解读
(1)创建 user 结构体实例
- user{ID: 1, Name: "张三", Age: 18},
- user{ID: 2, Name: "李四", Age: 19},
复制代码
- user{ID: 1, Name: "张三", Age: 18} 创建一个 user 实例,ID 为 1,名字为 "张三",年龄为 18。
- user{ID: 2, Name: "李四", Age: 19} 创建一个 user 实例,ID 为 2,名字为 "李四",年龄为 19。
(2)实现 GetKey[int64] 接口
- 上述 user 结构体实现了 GetKey[int64] 接口,因为 user 结构体定义了 Get() 方法,而且返回值范例为 int64
(3)创建并初始化切片
- userList := []GetKey[int64]{
- user{ID: 1, Name: "张三", Age: 18},
- user{ID: 2, Name: "李四", Age: 19},
- }
复制代码
- 使用两个 user 实例来初始化一个切片 (slice)。
- 该切片的范例是 []GetKey[int64],体现这个切片包罗实现了 GetKey[int64] 接口的元素。
(4)作用
- 创建并初始化一个包罗多个 user 实例的切片,让这个切片可以作为 GetKey[int64] 接口的实现来通报和使用。
- 这样的设计允许切片中的每个 user 实例都具备 Get 方法,从而可以在后续的泛型函数 listToMap 中使用这些 Get 方法来获取唯一键。
总结
- GetKey 是一个泛型接口,带有范例参数 T,该参数必须是可比较范例。
- 该接口要求实现者提供一个 Get 方法,返回范例为 T。
- 这是 Go 1.18 引入的泛型特性,允许编写更通用、更范例安全的代码。
相关知识点
接口
- 接口定义了方法聚集,恣意范例只要实现了这些方法,就实现了该接口
泛型
- 泛型允许定义通用的数据结构和函数,进步代码复用性。Go 1.18 开始引入泛型支持
- 泛型接口和方法通过范例参数举行约束
结构体
map
- map 在 Go 中用于存储键值对,是内建的数据结构
导入包
- fmt 包提供了格式化输入和输出功能,用于打印变量的值
(三) 示例3
- package _receiver
- import "fmt"
- // 定义一个泛型结构体 MyStruct
- // 该结构体接受一个类型参数 T,T 只能是 *int 或 *string
- type MyStruct[T interface{ *int | *string }] struct {
- Name string // 结构体的名字字段
- Data T // 结构体的数据字段,类型为 T
- }
- // 定义 MyStruct 结构体的泛型方法接收器
- // GetData 返回结构体中的 Data 字段
- func (myStruct MyStruct[T]) GetData() T {
- return myStruct.Data
- }
- // 主函数,演示 MyStruct 结构体和其方法的使用
- func ReceiverCase() {
- // 定义一个整型变量,并创建 MyStruct 实例
- data := 18
- myStruct := MyStruct[*int]{
- Name: "heheda",
- Data: &data, // 将整型变量的指针分配给 Data 字段
- }
- // 调用 GetData 方法获取 Data 字段的值并打印
- data1 := myStruct.GetData()
- fmt.Println(*data1) // 解引用指针打印值,输出 18
- // 定义一个字符串变量,并创建 MyStruct 实例
- str := "abcdefg"
- myStruct1 := MyStruct[*string]{
- Name: "heheda",
- Data: &str, // 将字符串变量的指针分配给 Data 字段
- }
- // 调用 GetData 方法获取 Data 字段的值并打印
- str1 := myStruct1.GetData()
- fmt.Println(*str1) // 解引用指针打印值,输出 "abcdefg"
- }
复制代码 这段代码展示了如安在 Go 语言中使用泛型定义结构体和方法接收器,以下是对代码各部分的解释:
1.包和导入
- package _receiver
- import "fmt"
复制代码 导入 fmt 包用于格式化输入输出
2.定义泛型结构体
- type MyStruct[T interface{ *int | *string }] struct {
- Name string
- Data T
- }
复制代码
- MyStruct 是一个泛型结构体,结构体内包罗两个字段:Name(范例为 string)和 Data(泛型范例 T)
- 这里 T 被约束为 *int 或 *string 范例
3.定义泛型方法接收器
- func (myStruct MyStruct[T]) GetData() T {
- return myStruct.Data
- }
复制代码
- GetData 是 MyStruct 的方法,这个方法担当一个泛型范例 T,返回 MyStruct 结构体中的 Data 字段
4.主函数 ReceiverCase
- func ReceiverCase() {
- data := 18
- myStruct := MyStruct[*int]{
- Name: "heheda",
- Data: &data,
- }
- data1 := myStruct.GetData()
- fmt.Println(*data1)
- str := "abcdefg"
- myStruct1 := MyStruct[*string]{
- Name: "heheda",
- Data: &str,
- }
- str1 := myStruct1.GetData()
- fmt.Println(*str1)
- }
复制代码
- 创建一个整型变量 data 并取其指针赋值给 MyStruct 实例 myStruct 的 Data 字段
- 调用 GetData 方法获取 Data 字段的值并打印
- 创建一个字符串变量 str 并取其指针赋值给 MyStruct 实例 myStruct1 的 Data 字段
- 调用 GetData 方法获取 Data 字段的值并打印
相关知识点
(1)泛型
- 泛型允许定义通用的数据结构和函数,加强代码复用性。Go 1.18 开始引入泛型支持
- 泛型范例参数通过范例约束举行限制,如本例中的 interface{ *int | *string }
(2)结构体
- 结构体是一种复合数据范例,可以包罗多个字段,允许将相关的数据构造在一起
(3)方法接收器
- 方法接收器是指与某个范例(如结构体或接口)关联的方法。在本例中,我们定义了 MyStruct 范例的泛型方法接收器 GetData
(4)指针
- 指针保存了变量的内存地址,在 Go 中,使用 & 符号获取一个变量的指针,使用 * 符号解引用指针获取指针指向的值
(5)导入包
- fmt 包提供了格式化输入和输出功能,用于打印变量的值
可以实验运行和修改代码,进一步理解这些概念。
main.go
- package main
- import (
- "context"
- _case "gomod/genetic-T/case"
- "os"
- "os/signal"
- )
- func main() {
- _case.TTypeCase()
- _case.TTypeCase1()
- _case.InterfaceCase()
- _receiver.ReceiverCase()
- ctx, stop := signal.NotifyContext(context.Background(), os.Interrupt, os.Kill)
- defer stop()
- <-ctx.Done()
- }
复制代码
免责声明:如果侵犯了您的权益,请联系站长,我们会及时删除侵权内容,谢谢合作!更多信息从访问主页:qidao123.com:ToB企服之家,中国第一个企服评测及商务社交产业平台。 |