文章目录
- Go 1.18版本引入了泛型(Generics)特性,这是Go语言自发布以来最重大的语言特性变更之一。泛型是一种允许在函数或类型定义中使用“类型变量”的编程特性,泛型允许你编写可以处理多种类型的函数和数据结构,而不需要为每种类型重复编写代码。 泛型的引入解决了Go语言长期以来缺乏灵活性的问题,特别是在处理集合、算法等通用场景时,显著减少了重复代码。
- Go还引入了非常多全新的概念:• 类型形参 (Type parameter)• 类型实参(Type argument)• 类型形参列表( Type parameter list)• 类型约束(Type constraint)• 实例化(Instantiations)• 泛型类型(Generic type)• 泛型接收器(Generic receiver)• 泛型函数(Generic function)
- 合理使用类型约束:在使用泛型时,尽量明确类型约束,避免滥用any类型,以确保代码的类型安全。 避免过度泛化:虽然泛型可以提升代码的灵活性,但过度使用可能导致代码难以理解和维护。 结合接口使用:在某些场景下,可以结合接口与泛型,进一步扩展代码的复用性。
- 泛型函数通过在函数名后添加类型参数列表(用方括号表示)来定义。例如,一个通用的求和函数可以支持多种数值类型。 案例1: package main import “fmt” // 定义泛型函数,支持int和float64类型 func Sum[T int | float64](a, b T) T { return a + b } func main() { fmt.Println(Sum(1, 2)) // 输出: 3 fmt.Println(Sum(1.5, 2.5)) // 输出: 4.0 } 案例2: package main import “fmt” // 定义一个泛型函数,T是类型参数 func PrintSlice[T any](s []T) { for _, v := range s { fmt.Printf(“%v “, v) } fmt.Println() } func main() { // 使用int切片 PrintSlice[int]([]int{1, 2, 3}) // 使用string切片(类型参数可以省略,编译器可以推断) PrintSlice([]string{“a”, “b”, “c”}) }
- 泛型结构体允许定义一个通用的数据结构,可以存储任意类型的值。示例代码: package main import “fmt” // 定义泛型结构体 type Box[T any] struct { Value T } func main() { intBox := Box[int]{Value: 42} strBox := Box[string]{Value: “Hello”} fmt.Println(intBox.Value) // 输出: 42 fmt.Println(strBox.Value) // 输出: Hello }
- 除了泛型函数,Go还支持泛型类型: package main import “fmt” // 定义一个泛型栈类型 type Stack[T any] struct { items []T } func (s *Stack[T]) Push(item T) { s.items = append(s.items, item) } func (s *Stack[T]) Pop() T { if len(s.items) == 0 { panic(“stack is empty”) } item := s.items[len(s.items)-1] s.items = s.items[:len(s.items)-1] return item } func main() { intStack := Stack[int]{} intStack.Push(1) intStack.Push(2) fmt.Println(intStack.Pop()) // 2 stringStack := Stack[string]{} stringStack.Push(“hello”) stringStack.Push(“world”) fmt.Println(stringStack.Pop()) // world }
- 泛型非常适合用于实现通用的集合操作,例如查找切片中的最大值。示例代码: package main import “fmt” // 查找切片中的最大值 func Max[T int | float64](slice []T) T { if len(slice) == 0 { var zero T return zero } max := slice[0] for _, v := range slice[1:] { if v > max { max = v } } return max } func main() { intSlice := []int{1, 2, 3, 4} floatSlice := []float64{1.1, 2.2, 3.3} fmt.Println(Max(intSlice)) // 输出: 4 fmt.Println(Max(floatSlice)) // 输出: 3.3 }
- 泛型还可以用于实现通用的数据结构,例如队列。 示例代码: package main import “fmt” // 定义泛型队列 type Queue[T any] struct { items []T } func (q *Queue[T]) Enqueue(item T) { q.items = append(q.items, item) } func (q *Queue[T]) Dequeue() (T, bool) { if len(q.items) == 0 { var zero T return zero, false } item := q.items[0] q.items = q.items[1:] return item, true } func main() { queue := Queue[int]{} queue.Enqueue(1) queue.Enqueue(2) item, ok := queue.Dequeue() if ok { fmt.Println(item) // 输出: 1 } }
- type Repository[T any] interface { GetByID(id int) (*T, error) Create(entity *T) error Update(entity *T) error Delete(id int) error } type GormRepository[T any] struct { db *gorm.DB } func (r *GormRepository[T]) GetByID(id int) (*T, error) { var entity T err := r.db.First(&entity, id).Error if err != nil { return nil, err } return &entity, nil } // 其他方法实现…
- // 过滤切片 func Filter[T any](slice []T, predicate func(T) bool) []T { var result []T for _, item := range slice { if predicate(item) { result = append(result, item) } } return result } // 检查元素是否存在 func Contains[T comparable](slice []T, target T) bool { for _, item := range slice { if item == target { return true } } return false } func main() { numbers := []int{1, 2, 3, 4, 5, 6} even := Filter(numbers, func(n int) bool { return n%2 == 0 }) fmt.Println(even) // [2 4 6] fmt.Println(Contains(numbers, 3)) // true fmt.Println(Contains(numbers, 7)) // false }
目录
- 一、泛型的概念与优势
- 1.1 泛型的介绍
- 1.2 Go的泛型
- 1.3 泛型的使用建议
- 二、泛型的使用
- 2.1 泛型函数
- 2.2 泛型结构体
- 2.3 泛型类型
- 三、泛型的实际应用
- 3.1 通用集合操作
- 3.2 泛型队列实现
- 3.3 数据库操作
- 3.4 通用工具函数
- 总结:
Go 1.18版本引入了泛型(Generics)特性,这是Go语言自发布以来最重大的语言特性变更之一。泛型是一种允许在函数或类型定义中使用“类型变量”的编程特性,泛型允许你编写可以处理多种类型的函数和数据结构,而不需要为每种类型重复编写代码。
泛型的引入解决了Go语言长期以来缺乏灵活性的问题,特别是在处理集合、算法等通用场景时,显著减少了重复代码。
Go还引入了非常多全新的概念:
• 类型形参 (Type parameter)
• 类型实参(Type argument)
• 类型形参列表( Type parameter list)
• 类型约束(Type constraint)
• 实例化(Instantiations)
• 泛型类型(Generic type)
• 泛型接收器(Generic receiver)
• 泛型函数(Generic function)
Go还引入了非常多全新的概念:
• 类型形参 (Type parameter)
• 类型实参(Type argument)
• 类型形参列表( Type parameter list)
• 类型约束(Type constraint)
• 实例化(Instantiations)
• 泛型类型(Generic type)
• 泛型接收器(Generic receiver)
• 泛型函数(Generic function)
- 合理使用类型约束:在使用泛型时,尽量明确类型约束,避免滥用
any类型,以确保代码的类型安全。
- 避免过度泛化:虽然泛型可以提升代码的灵活性,但过度使用可能导致代码难以理解和维护。
- 结合接口使用:在某些场景下,可以结合接口与泛型,进一步扩展代码的复用性。
any类型,以确保代码的类型安全。
泛型函数通过在函数名后添加类型参数列表(用方括号表示)来定义。例如,一个通用的求和函数可以支持多种数值类型。
案例1:
package main
import "fmt"
// 定义泛型函数,支持int和float64类型
func Sum[T int | float64](a, b T) T {
return a + b
}
func main() {
fmt.Println(Sum(1, 2)) // 输出: 3
fmt.Println(Sum(1.5, 2.5)) // 输出: 4.0
}
案例2:
package main
import "fmt"
// 定义一个泛型函数,T是类型参数
func PrintSlice[T any](s []T) {
for _, v := range s {
fmt.Printf("%v ", v)
}
fmt.Println()
}
func main() {
// 使用int切片
PrintSlice[int]([]int{1, 2, 3})
// 使用string切片(类型参数可以省略,编译器可以推断)
PrintSlice([]string{"a", "b", "c"})
}
泛型结构体允许定义一个通用的数据结构,可以存储任意类型的值。
示例代码:
package main
import "fmt"
// 定义泛型结构体
type Box[T any] struct {
Value T
}
func main() {
intBox := Box[int]{Value: 42}
strBox := Box[string]{Value: "Hello"}
fmt.Println(intBox.Value) // 输出: 42
fmt.Println(strBox.Value) // 输出: Hello
}
除了泛型函数,Go还支持泛型类型:
package main
import "fmt"
// 定义一个泛型栈类型
type Stack[T any] struct {
items []T
}
func (s *Stack[T]) Push(item T) {
s.items = append(s.items, item)
}
func (s *Stack[T]) Pop() T {
if len(s.items) == 0 {
panic("stack is empty")
}
item := s.items[len(s.items)-1]
s.items = s.items[:len(s.items)-1]
return item
}
func main() {
intStack := Stack[int]{}
intStack.Push(1)
intStack.Push(2)
fmt.Println(intStack.Pop()) // 2
stringStack := Stack[string]{}
stringStack.Push("hello")
stringStack.Push("world")
fmt.Println(stringStack.Pop()) // world
}
泛型非常适合用于实现通用的集合操作,例如查找切片中的最大值。
示例代码:
package main
import "fmt"
// 查找切片中的最大值
func Max[T int | float64](slice []T) T {
if len(slice) == 0 {
var zero T
return zero
}
max := slice[0]
for _, v := range slice[1:] {
if v > max {
max = v
}
}
return max
}
func main() {
intSlice := []int{1, 2, 3, 4}
floatSlice := []float64{1.1, 2.2, 3.3}
fmt.Println(Max(intSlice)) // 输出: 4
fmt.Println(Max(floatSlice)) // 输出: 3.3
}
泛型还可以用于实现通用的数据结构,例如队列。
示例代码:
package main
import "fmt"
// 定义泛型队列
type Queue[T any] struct {
items []T
}
func (q *Queue[T]) Enqueue(item T) {
q.items = append(q.items, item)
}
func (q *Queue[T]) Dequeue() (T, bool) {
if len(q.items) == 0 {
var zero T
return zero, false
}
item := q.items[0]
q.items = q.items[1:]
return item, true
}
func main() {
queue := Queue[int]{}
queue.Enqueue(1)
queue.Enqueue(2)
item, ok := queue.Dequeue()
if ok {
fmt.Println(item) // 输出: 1
}
}
type Repository[T any] interface {
GetByID(id int) (*T, error)
Create(entity *T) error
Update(entity *T) error
Delete(id int) error
}
type GormRepository[T any] struct {
db *gorm.DB
}
func (r *GormRepository[T]) GetByID(id int) (*T, error) {
var entity T
err := r.db.First(&entity, id).Error
if err != nil {
return nil, err
}
return &entity, nil
}
// 其他方法实现...
// 过滤切片
func Filter[T any](slice []T, predicate func(T) bool) []T {
var result []T
for _, item := range slice {
if predicate(item) {
result = append(result, item)
}
}
return result
}
// 检查元素是否存在
func Contains[T comparable](slice []T, target T) bool {
for _, item := range slice {
if item == target {
return true
}
}
return false
}
func main() {
numbers := []int{1, 2, 3, 4, 5, 6}
even := Filter(numbers, func(n int) bool {
return n%2 == 0
})
fmt.Println(even) // [2 4 6]
fmt.Println(Contains(numbers, 3)) // true
fmt.Println(Contains(numbers, 7)) // false
}
Go语言的泛型功能为开发者提供了编写灵活、可复用代码的强大工具。通过泛型函数、泛型结构体及实际案例,开发者可以轻松应对多种数据类型的处理需求。在实际开发中,合理使用泛型不仅能减少重复代码,还能提升代码的可维护性和扩展性。
到此这篇关于Go语言泛型使用及应用的文章就介绍到这了,更多相关Go语言泛型使用内容请搜索风君子博客以前的文章或继续浏览下面的相关文章希望大家以后多多支持风君子博客!
您可能感兴趣的文章:
- 详解Go语言中泛型的实现原理与使用
- 如何使用Go语言实现基于泛型的Jaccard相似度算法
- Go语言利用泛型封装常见的Map操作
- Go语言泛型打造优雅的切片工具库