做私单的网站,高端html5网站设计工作室织梦模板 dedecms5.7,wordpress 文章选择器,个人网页设计开题报告文章目录 泛型类型参数类型实例化类型约束类型集并集 交集 泛型接收者泛型方法泛型接口两种接口类型泛型接口 泛型实现通用数据结构数组链表数组队列 本节项目地址#xff1a;06-GenericsQueue
泛型 如果你经常要分别为不同的类型写完全相同逻辑的代码#xff0c;那么… 文章目录 泛型类型参数类型实例化类型约束类型集并集 交集 泛型接收者泛型方法泛型接口两种接口类型泛型接口 泛型实现通用数据结构数组链表数组队列 本节项目地址06-GenericsQueue
泛型 如果你经常要分别为不同的类型写完全相同逻辑的代码那么使用泛型将是最合适的选择 类型参数
类型形参列表T int | float64
func min[T int | float64](a, b T) T {if a b {return a}return b
}func function01() {x : min[int](10, 20)y : min[float64](0.1, -0.2)fmt.Println(x, y) // 10 -0.2
}类型形参T类型实参int
类型实例化
向 min 函数提供类型参数在本例中为 int 和 float64 称为实例化。
类型实例化
编译器在整个泛型函数或类型中将所有类型形参替换为它们各自的类型实参。编译器验证每个类型参数是否满足相应的约束。
fmin : min[float64] // 类型实例化
z : fmin(1.1, 2.2)
fmt.Println(z) // 1.1类型约束
Go支持将类型约束单独拿出来定义到接口中从而让代码更容易维护。
type Int interface {int | int8 | int16 | int32 | int64
}
type Uint interface {uint | uint8 | uint16 | uint32
}
type Float interface {float32 | float64
}
type Slice[T Int | Uint | Float] []T // 使用 | 将多个接口类型组合两种常见的类型约束
类型约束字面量通常 interface{} 可省略
func max[T interface{int | float64}](a, b T) T {if a b {return a}return b
}约束类型事先定义并支持复用
type Value interface {int | float64
}func max1[T Value](a, b T) T {if a b {return a}return b
}几种语法错误
定义泛型类型基础类型不能只有类型形参
// 类型形参不能单独使用
type Type[T int | float32] T类型约束语义被编译器误认为是表达式
// 误认为定义一个存放切片的数组长度 T * int
type NewType [T * int][]T// | 误以为是按位或
type NewType[T *int | *float32] []T解决办法可使用 interface{} 包裹或加上逗号
type NewType[T interface{*int}] []T
type NewType[T interface{*int | *float64}] []T// 类型约束只有一个类型可以添加逗号消除歧义
type NewType[T *int,] []T类型集
从 Go 1.18 开始一个接口不仅可以嵌入其他接口还可以嵌入任何类型、类型的联合或共享相同底层类型的无限类型集合。
当用作类型约束时由接口定义的类型集精确地指定允许作为相应类型参数的类型。
| 符号
T1 | T2表示类型约束为 T1 和 T2 这两个类型的并集
~ 符号
~T 表示所有底层类型是 T 的类型集合~ 后面只能是基本类型
type Map[K int | string, V float32 | float64] map[K]V
type IValue interface {~string | ~int
}
type MyInt intfunc sum[T IValue](a []T) (res T) {for _, e : range a {res e}return
}func function04() {m : Map[int, float64]{}m[1] 1.0m[2] 2.0fmt.Println(m) // map[1:1 2:2]a : []MyInt{1, 2, 3}fmt.Println(sum(a)) // 6
}并集 交集
// 类型并集
type Int interface {~int | ~int8 | ~int16 | ~int32 | ~int64 | ~uint | ~uint8 | ~uint16 | ~uint32 | ~uint64
}
type Uint interface {~uint | ~uint8 | ~uint16 | ~uint32 | ~uint64
}
// 类型交集
type A interface {IntUint~string
}类型取并集时用 | 连接多个类型这些类型必须不交集相交类型是接口不受约束
// 错误overlapping terms ~int and int
type B interface {int | ~int
}// 正确
type B interface {int | interface{ ~int }
}并集中不能有类型实参
// 错误
type C[T int | string] interface {~float64 | T
}接口不能直接或间接并入自己
// 错误D嵌入E间接并入了自己
type D interface {E
}type E interface {D
}
// 错误
type F interface {int | ~float64 | F
}带方法的接口不能写入接口的并集中
type ReadWriter[T any] interface {Read(data T) (newData T)Writer(data T) error
}
// 错误
type G interface {int | ReadWriter[int]
}泛型接收者
定义一个新类型后可以给新类型添加方法那么同样也可以给泛型类型添加方法如下
本例子为泛型类型 MyFloat[T] 定义了类型方法 avg计算数组平均值在使用泛型类型前始终需要先对类型实参实例化
type MyFloat[T ~float32 | ~float64] []Tfunc (mf MyFloat[T]) avg() T {var res Tfor _, e : range mf {res e}return res / T(len(mf))
}func function05() {var fa MyFloat[float32] []float32{1.0, 2.1, 3.2}fmt.Println(fa.avg()) // 2.1000001f64 : MyFloat[float64]{1.0, 2.1, 3.2}fmt.Println(f64.avg()) // 2.1
}泛型方法
Go 目前不支持泛型方法如下
type MyStruct struct {}
// 错误Method cannot have type parameters
func (ms MyStruct) Add[T int | string](other T) MyStruct {}在方法中使用泛型可以通过接收者来使用如下
type MyStruct[T int | string] struct {value T
}func (ms MyStruct[T]) Add(other T) MyStruct[T] {ms.value otherreturn ms
}func function06() {a : MyStruct[int]{1}b : MyStruct[string]{1}fmt.Println(a.Add(2), b.Add(34)) // {3} {134}
}泛型接口
两种接口类型 基本接口接口中只有方法 一般接口接口中不只有方法还有类型
一般接口不能用来定义变量只能用于泛型的类型约束中。
// 基本接口
type MyErr interface {Error() string
}// 一般接口
type MyUint interface {~uint | ~uint8 | ~uint16
}func function07() {var a MyErr fmt.Errorf(这是基本接口)fmt.Println(a.Error()) // 这是基本接口// 错误不能使用一般接口定义变量// var b MyUint
}泛型接口
泛型接口Processer[T] 在实例化后即为基本接口可以用于创建变量如下 XML 类型实现了 Processer[string] 接口
type Processer[T any] interface {Process(data T) TSave(data T) error
}type XML struct{}func (x XML) Process(data string) (newData string) {return
}
func (x XML) Save(data string) error {return errors.New()
}func function08() {var a Processer[string] XML{}a.Process()a.Save()
}泛型接口ProcesserNormal[T] 实例化后即为一般接口只能用于类型约束不能用于定义变量。笔者没探索出来有啥用 O(∩_∩)O
type ProcesserNormal[T any] interface {int | ~struct{ value T }Process(data T) TSave(data T) error
}其余需要注意的
匿名结构体不支持泛型
type TypeStruct[T int | string] struct {Name stringData []T
}func function03() {x : TypeStruct[int]{Cauchy, []int{1, 2, 3}}fmt.Println(x) // {Cauchy [1 2 3]}/* 匿名结构体不支持泛型y : struct[T []int|[]string]{Name stringData T}[int]{AQ,[]int{1, 2, 3},}*/
}当你需要针对不同类型书写同样的逻辑使用泛型来简化代码是最好的 (比如你想写个队列写个链表、栈、堆之类的数据结构 泛型实现通用数据结构
通用数据结构实现参考https://pkg.go.dev/github.com/emirpasic/gods/v2
数组链表
下述实现提及 Go 内置的一个可比较对象类型 —— comparable接口。comparable 接口是由所有可比较类型实现的接口只能用作类型参数约束不能用作变量类型。
泛型容器接口 containers/containers.go所有容器都需要实现其内部方法
type Container[T any] interface {Empty() boolSize() intClear()Values() []TString() string
}泛型链表接口 lists/lists.go所有链表都要实现其内部方法
type List[T comparable] interface {Get(index int) (T, bool)Remove(index int)Add(values ...T)Contains(values ...T) boolSort(comparator utils.Comparator[T])Insert(index int, values ...T)Set(index int, value T)containers.Container[T]
}泛型可比较对象 utils/comparator.go
type Comparator[T any] func(x, y T) int泛型数组链表 lists/arraylist/arraylist.go
package arraylistimport (06-GenericsTest/lists06-GenericsTest/utilsfmtslicesstrings
)// 断言 List 实现接口 lists.List
var _ lists.List[int] (*List[int])(nil)// List 链表结构
type List[T comparable] struct {elements []Tsize int
}const (growthFactor float32(2.0) // 扩容因子shrinkFactor float32(0.25) // 缩容因子
)// New 创建链表
func New[T comparable](values ...T) *List[T] {list : List[T]{}if len(values) 0 {list.Add(values...)}return list
}// Add 向链表末尾添加元素
func (l *List[T]) Add(values ...T) {l.growBy(len(values))for _, value : range values {l.elements[l.size] valuel.size}
}// Get 获取下标 index 的元素
func (l *List[T]) Get(index int) (T, bool) {if !l.withinRange(index) {var t Treturn t, false}return l.elements[index], true
}// Remove 移除下标 index 的元素
func (l *List[T]) Remove(index int) {if !l.withinRange(index) {return}clear(l.elements[index : index1])copy(l.elements[index:], l.elements[index1:l.size])l.size--l.shrink()
}// Contains 判断是否包含元素
func (l *List[T]) Contains(values ...T) bool {for _, searchValue : range values {found : falsefor i : 0; i l.size; i {if l.elements[i] searchValue {found truebreak}}if !found {return false}}return true
}// Values 获取链表元素切片
func (l *List[T]) Values() []T {newElements : make([]T, l.size, l.size)copy(newElements, l.elements[:l.size])return newElements
}// IndexOf 获取元素所在下标
func (l *List[T]) IndexOf(value T) int {if l.size 0 {return -1}for index, element : range l.elements {if element value {return index}}return -1
}// Empty 判断链表为空
func (l *List[T]) Empty() bool {return l.size 0
}// Size 获取元素个数
func (l *List[T]) Size() int {return l.size
}// Clear 清空链表
func (l *List[T]) Clear() {l.size 0l.elements []T{}
}// Sort 链表元素排序
func (l List[T]) Sort(comparator utils.Comparator[T]) {if len(l.elements) 2 {return}slices.SortFunc(l.elements[:l.size], comparator)
}// Swap 交换两个元素
func (l *List[T]) Swap(i, j int) {if l.withinRange(i) l.withinRange(j) {l.elements[i], l.elements[j] l.elements[j], l.elements[i]}
}// Insert 指定位置插入
func (l *List[T]) Insert(index int, values ...T) {if !l.withinRange(index) {if index l.size {l.Add(values...)}return}length : len(values)l.growBy(length)l.size lengthcopy(l.elements[indexlength:], l.elements[index:l.size-length])copy(l.elements[index:], values)
}// Set 指定位置设置元素
func (l *List[T]) Set(index int, value T) {if !l.withinRange(index) {if index l.size {l.Add(value)}return}l.elements[index] value
}// String 字符串显示链表
func (l *List[T]) String() string {str : ArrayList: values : make([]string, 0, l.size)for _, value : range l.elements[:l.size] {values append(values, fmt.Sprintf(%v, value))}str [ strings.Join(values, , ) ]return str
}// withinRange 判断是否越界
func (l *List[T]) withinRange(index int) bool {return index 0 index l.size
}// resize 链表底层切片重新分配地址
func (l *List[T]) resize(cap int) {newElements : make([]T, cap)copy(newElements, l.elements)l.elements newElements
}// growBy 判断是否增加 n 各元素需要扩容
func (l *List[T]) growBy(n int) {currentCapacity : cap(l.elements)if l.sizen currentCapacity {newCapacity : int(growthFactor * float32(currentCapacityn))l.resize(newCapacity)}
}// shrink 缩容
func (l *List[T]) shrink() {if shrinkFactor 0.0 {return}currentCapacity : cap(l.elements)if l.size int(float32(currentCapacity)*shrinkFactor) {l.resize(l.size)}
}
数组队列
泛型队列接口 queues/queues.go
// Queue 泛型队列接口
type Queue[T comparable] interface {Enqueue(value T)Dequeue() (value T, ok bool)Peek() (value T, ok bool)containers.Container[T]
}泛型数组队列 queues/arrayqueue/arrayqueue.go
package arrayqueueimport (06-GenericsTest/lists/arraylist06-GenericsTest/queuesfmtstrings
)var _ queues.Queue[int] (*Queue[int])(nil)// Queue 队列结构
type Queue[T comparable] struct {list *arraylist.List[T]
}// New 创建队列
func New[T comparable]() *Queue[T] {return Queue[T]{list: arraylist.New[T]()}
}// Enqueue 入队
func (q *Queue[T]) Enqueue(value T) {q.list.Add(value)
}// Dequeue 出队
func (q *Queue[T]) Dequeue() (value T, ok bool) {value, ok q.list.Get(0)if ok {q.list.Remove(0)}return
}// Peek 队头元素
func (q *Queue[T]) Peek() (value T, ok bool) {return q.list.Get(0)
}// Empty 判断队列为空
func (q *Queue[T]) Empty() bool {return q.list.Empty()
}// Size 获取队列元素个数
func (q *Queue[T]) Size() int {return q.list.Size()
}// Clear 清空队列
func (q *Queue[T]) Clear() {q.list.Clear()
}// Values 获取队列元素切片
func (q *Queue[T]) Values() []T {return q.list.Values()
}// String 字符串显示队列
func (q *Queue[T]) String() string {str : ArrayQueue: values : []string{}for _, value : range q.list.Values() {values append(values, fmt.Sprintf(%v, value))}str [ strings.Join(values, , ) ]return str
}参考https://blog.csdn.net/u014374975/article/details/133905842