123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130 |
- # Go 泛型介绍
-
- 清和
- 2022-01-22
- chenqh721@foxmail.com
-
-
- ## Agenda
- - Why generic
- - Type parameter
- - Constraint
- - Some cases
-
-
- ## Why generic
-
- ## Why generic
-
- .code codes/atomic.go /OMIT/,/OMIT/
-
- - 每种类型都得实现一遍
-
- ## Why generic
-
- .code codes/atomic.go /INTR OMIT/,/INTR OMIT/
-
- - 无法在编译期检查出错误
- - 类型转换影响性能
-
-
- ## Type parameters
-
- ## Type parameters
-
- 泛型代码中会用到抽象的数据类型,这个类型叫做`type parameters`. 在运行泛型代码的时候,类型形参会被替换为类型实参。
-
- .code codes/print.go /PRINT OMIT/,/PRINT OMIT/
-
- 类型T该如何被定义?
-
-
- - 类型参数类似于传统的非类型参数
- - 需要区分类型参数与非类型参数
-
- ==> **需要另外一个可选参数列表来确定类型参数**
-
-
- ## Type parameter
-
- - 在普通参数前面
- - 使用方括号[ ]包围
- - 类型参数也有「元类型」,也即constraint(约束)
-
- .code codes/print.go /GEN OMIT/,/GEN OMIT/
-
- 以上示例代码中:
-
- - `T` 是一个**type parameter**
- - **any**是一个**constraint**,意思是T可以是任意类型
- - `T` 可以用来规定参数s的类型,也可以用在函数体内
- - 不同于普通参数,类型参数名`T` 不可省略
-
- ## Type parameter
-
- 调用泛型函数
-
- .play codes/print.go /CALL OMIT/,/CALL OMIT/
-
- - 需指定类型参数,类型参数写在中括号内
- - 有多个类型参数时,使用逗号分隔
-
-
- ## Constraint
-
- ## Constraint
- 接下来来个稍微复杂点的例子:
-
- .play codes/stringfy.go /START OMIT/,/END OMIT/
-
- - T 可以是任意类型
- - 类型 T 可能并没有String方法
-
- **以上代码并不能运行**
-
-
- ## Constraint
-
- 在其他有泛型的语言中也会出现类似的情况。
-
- 例如,在C++中。
-
- 调用v.String()是允许的,在编译过程中,如果发现实际调用时传入的类型实参T没有String方法,那么会报错误,如果有String方法,可以正常编译。
-
- 也就是说:**C++实际上对类型是没有明确限制的**
-
-
- ## Constraint
-
- 出于语言风格考虑,Go语言不会采用上述方案。
-
- - In Go we don't refer to names, such as, in this case, String, and hope that they exist. Go resolves all names to their declarations when they are seen.
- - Another reason is that Go is designed to support programming at scale.
-
- Details see: [Type Parameters Proposal # Constraint](https://go.googlesource.com/proposal/+/refs/heads/master/design/43651-type-parameters.md#constraints)
-
- 通常,我们希望泛型代码中的类型参数满足一定的条件,这些条件被称为约束(Constraints)。
-
- Constraints必须能够同时限制调用方传入的类型参数以及泛型函数的具体实现:
- 1. **调用泛型函数时传入的类型实参必须满足Constraints**
- 2. **实现泛型函数时必须用Constraints允许的方式来使用这些值(e. g. + - * / > ....)**
-
-
- ## Constraint
-
- 首先看一个特殊的constraint:**any**,表示类型参数允许是任何类型。any约束下各类型(T)允许的操作有:
-
- - 申明对应类型的变量
- - 给此类型变量重新赋一个相同类型的值
- - 将此类型变量传给其他函数或者作为返回值返回
- - 取此类型变量的地址
- - 强制类型转换为interface{}类型或者赋值给interface{}类型的变量
- - 将类型T强转为类型T(允许但是没啥用)
- - 使用类型断言将interface转换为类型T
- - 在type switch中使用此类型作为其中一个case
- - 定义及使用此类型的复合类型(例如切片)
- - 将此类型作为预定义类型的参数,比如new函数
-
- ## Constraint
-
|