golang 基础 泛型编程
(一) 示例1package _case
import "fmt"
// 定义用户类型的结构体
type user struct {
ID int64
Name string
Ageuint8
}
// 定义地址类型的结构体
type address struct {
ID int
Province string
City string
}
// 集合转列表函数,接受一个 map,返回一个切片
func mapToList(mp mapT) []T {
// 创建切片,长度与 map 的长度相同
list := make([]T, len(mp))
var i int
for _, data := range mp {
list = data
i++
}
return list
}
// 打印通道内容的函数,接受一个通道并打印通道中的每一个数据
func myPrintln(ch chan T) {
for data := range ch {
fmt.Println(data)
}
}
// 主函数,执行类型转换和打印
func TTypeCase() {
// 创建一个用户类型的 map
userMp := make(mapuser, 0)
// 向 map 中添加用户数据
userMp = user{ID: 1, Name: "heheda", Age: 18}
userMp = user{ID: 2, Name: "Jerry", Age: 20}
userMp = user{ID: 3, Name: "Tom", Age: 22}
// 将用户 map 转换为用户列表
userList := mapToList(userMp)
// 创建用户类型的通道,并启动 goroutine 打印通道数据
ch := make(chan user)
go myPrintln(ch)
// 将用户列表中的数据发送到通道
for _, u := range userList {
ch <- u
}
close(ch)
// 创建一个地址类型的 map
addrMp := make(mapaddress, 0)
// 向 map 中添加地址数据
addrMp = address{ID: 1, Province: "湖南", City: "长沙"}
addrMp = address{ID: 2, Province: "广东", City: "揭阳"}
// 将地址 map 转换为地址列表
addrList := mapToList(addrMp)
// 创建地址类型的通道,并启动 goroutine 打印通道数据
ch1 := make(chan address)
go myPrintln(ch1)
// 将地址列表中的数据发送到通道
for _, addr := range addrList {
ch1 <- addr
}
close(ch1)
}
// 泛型切片的定义
type List []T
// 泛型 map 的定义
// 声明两个泛型,分别为 k 、 v
type MapT mapv
// 泛型通道的定义
type Chan chan T
func TTypeCase1() {
// mapuser -> MapT
userMp := make(MapT, 0)
userMp = user{ID: 1, Name: "heheda", Age: 18}
userMp = user{ID: 2, Name: "Jerry", Age: 20}
userMp = user{ID: 3, Name: "Tom", Age: 22}
var userList List
userList = mapToList(userMp)
ch := make(Chan)
go myPrintln(ch)
for _, u := range userList {
ch <- u
}
close(ch)
// mapaddress -> MapT
addrMp := make(MapT, 0)
addrMp = address{ID: 1, Province: "湖南", City: "长沙"}
addrMp = address{ID: 2, Province: "广东", City: "揭阳"}
var addrList List
addrList = mapToList(addrMp)
ch1 := make(Chan)
go myPrintln(ch1)
for _, addr := range addrList {
ch1 <- addr
}
close(ch1)
}
https://i-blog.csdnimg.cn/direct/0c145988d82440f289d8907cbb51b8c7.png
这段代码展示了如何使用 Go 语言中的泛型、结构体和通道举行数据处理和打印。以下是对代码各部分的解释:
1.包和导入
package _case
import "fmt"
[*] 导入 fmt 包用于格式化输入输出
2.结构体定义
[*]user 结构体 有三个字段:ID(范例 int64)、Name(范例 string)和 Age(范例 uint8)
[*]address 结构体 有三个字段:ID(范例 int)、Province(范例 string)和 City(范例 string)
3.泛型函数
func mapToList(mp mapT) []T {
list := make([]T, len(mp))
var i int
for _, data := range mp {
list = data
i++
}
return list
}
[*]mapToList 是一个泛型函数,它担当一个 map 范例的参数 mp,并将其转换为切片(列表)
[*]这里使用了两个泛型范例参数:k(可比较范例)和 T(恣意范例)
4.打印通道内容的泛型函数
func myPrintln(ch chan T) {
for data := range ch {
fmt.Println(data)
}
}
[*]myPrintln 是一个泛型函数,担当一个通道范例的参数 ch,并打印通道中的每一个数据
5.主函数 TTypeCase
func TTypeCase() {
userMp := make(mapuser, 0)
userMp = user{ID: 1, Name: "heheda", Age: 18}
userMp = user{ID: 2, Name: "Jerry", Age: 20}
userMp = user{ID: 3, Name: "Tom", Age: 22}
userList := mapToList(userMp)
ch := make(chan user)
go myPrintln(ch)
for _, u := range userList {
ch <- u
}
close(ch)
addrMp := make(mapaddress, 0)
addrMp = address{ID: 1, Province: "湖南", City: "长沙"}
addrMp = address{ID: 2, Province: "广东", City: "揭阳"}
addrList := mapToList(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
type MapT mapv
type Chan chan T 7.另一主函数 TTypeCase1
func TTypeCase1() {
// mapuser -> MapT
userMp := make(MapT, 0)
userMp = user{ID: 1, Name: "heheda", Age: 18}
userMp = user{ID: 2, Name: "Jerry", Age: 20}
userMp = user{ID: 3, Name: "Tom", Age: 22}
var userList List
userList = mapToList(userMp)
ch := make(Chan)
go myPrintln(ch)
for _, u := range userList {
ch <- u
}
close(ch)
// mapaddress -> MapT
addrMp := make(MapT, 0)
addrMp = address{ID: 1, Province: "湖南", City: "长沙"}
addrMp = address{ID: 2, Province: "广东", City: "揭阳"}
var addrList List
addrList = mapToList(addrMp)
ch1 := make(Chan)
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 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](list []T) mapT { mp := make(mapT, len(list)) // 创建 map,长度为列表长度 for _, data := range list { mp = data // 使用 Get() 方法获取键 } return mp}// 主函数,演示列表转 map 的操纵func InterfaceCase() { // 创建 user 列表,元素实现了 GetKey 接口 userList := []GetKey{ user{ID: 1, Name: "张三", Age: 18}, user{ID: 2, Name: "李四", Age: 19}, } // 创建 address 列表,元素实现了 GetKey 接口 addrList := []GetKey{ address{ID: 1, Province: "广东", City: "揭阳"}, address{ID: 2, Province: "湖南", City: "长沙"}, } // 将 user 列表转换为 map,并打印效果 userMp := listToMap](userList) fmt.Println(userMp) // 将 address 列表转换为 map,并打印效果 addrMp := listToMap](addrList) fmt.Println(addrMp)} https://i-blog.csdnimg.cn/direct/ca1f7bb9655e478bbc199cb0df6bba31.png
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 interface {
any
Get() T
} 这是一个泛型接口声明。具体来说,GetKey 接口担当一个范例参数 T,这个范例参数必须是一个可比较的范例 (comparable)
(1)定义泛型接口
type GetKey interface {
[*]GetKey 定义了一个泛型接口。
[*]T 是一个范例参数,它必须是一个可比较的范例 (comparable)。可比较范例体现可以使用 == 和 != 运算符举行比较,常见的可比较范例包括整数、浮点数、字符串以及指针等。
(2)嵌入 any 接口
[*]Go 1.18 引入了范例聚集 any,它是 interface{} 的别名,体现恣意范例
[*]在接口中嵌入 any 意味着该接口可以担当任何范例的实现
(3)定义方法
Get() T
[*]定义了一个方法 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 接口,而 address 实现了 GetKey 接口
6.列表转聚集函数
func listToMap](list []T) mapT {
mp := make(MapT, len(list))
for _, data := range list {
mp = data
}
return mp
}
[*]listToMap 是一个泛型函数,将 list 转换为 map
[*]函数参数 k 为键的范例,T 为实现 GetKey 接口的范例
[*]data.Get() 返回键,作为 map 的键
7.主函数 InterfaceCase
func InterfaceCase() {
userList := []GetKey{
user{ID: 1, Name: "张三", Age: 18},
user{ID: 2, Name: "李四", Age: 19},
}
addrList := []GetKey{
address{ID: 1, Province: "广东", City: "揭阳"},
address{ID: 2, Province: "湖南", City: "长沙"},
}
userMp := listToMap](userList)
fmt.Println(userMp)
addrMp := listToMap](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 接口
[*]上述 user 结构体实现了 GetKey 接口,因为 user 结构体定义了 Get() 方法,而且返回值范例为 int64
(3)创建并初始化切片
userList := []GetKey{
user{ID: 1, Name: "张三", Age: 18},
user{ID: 2, Name: "李四", Age: 19},
}
[*]使用两个 user 实例来初始化一个切片 (slice)。
[*]该切片的范例是 []GetKey,体现这个切片包罗实现了 GetKey 接口的元素。
(4)作用
[*]创建并初始化一个包罗多个 user 实例的切片,让这个切片可以作为 GetKey 接口的实现来通报和使用。
[*]这样的设计允许切片中的每个 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 struct {
Name string // 结构体的名字字段
Data T // 结构体的数据字段,类型为 T
}
// 定义 MyStruct 结构体的泛型方法接收器
// GetData 返回结构体中的 Data 字段
func (myStruct MyStruct) 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 struct {
Name string
Data T
}
[*]MyStruct 是一个泛型结构体,结构体内包罗两个字段:Name(范例为 string)和 Data(泛型范例 T)
[*]这里 T 被约束为 *int 或 *string 范例
3.定义泛型方法接收器
func (myStruct MyStruct) 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企服之家,中国第一个企服评测及商务社交产业平台。
页:
[1]