Keine Beschreibung

chapter1-why-generics.slide 3.5KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130
  1. # Go 泛型介绍
  2. 清和
  3. 2022-03-31
  4. qinghe.chen@tuya.com
  5. ## Agenda
  6. - Why generic
  7. - Type parameter
  8. - Constraint
  9. - Some cases
  10. ## Why generic
  11. ## Why generic
  12. .code codes/atomic.go /OMIT/,/OMIT/
  13. - 每种类型都得实现一遍
  14. ## Why generic
  15. .code codes/atomic.go /INTR OMIT/,/INTR OMIT/
  16. - 无法在编译期检查出错误
  17. - 类型转换影响性能
  18. ## How Generics
  19. ## Type parameters
  20. 泛型代码中会用到抽象的数据类型,这个类型叫做`type parameters`(类型参数). 在运行泛型代码的时候,类型形参会被替换为类型实参。
  21. .code codes/print.go /PRINT OMIT/,/PRINT OMIT/
  22. 类型T该如何被定义?
  23. - 类型参数类似于传统的非类型参数
  24. - 需要区分类型参数与非类型参数
  25. ==> **需要另外一个可选参数列表来确定类型参数**
  26. ## Type parameter
  27. - 在普通参数前面
  28. - 使用方括号[ ]包围
  29. - 类型参数也有「元类型」,也即constraint(约束)
  30. .code codes/print.go /GEN OMIT/,/GEN OMIT/
  31. 以上示例代码中:
  32. - `T` 是一个**type parameter**
  33. - **any**是一个**constraint**,意思是T可以是任意类型
  34. - `T` 可以用来规定参数s的类型,也可以用在函数体内
  35. - 不同于普通参数,类型参数名`T` 不可省略
  36. ## Type parameter
  37. 调用泛型函数
  38. .play codes/print.go /CALL OMIT/,/CALL OMIT/
  39. - 需指定类型参数,类型参数写在中括号内
  40. - 有多个类型参数时,使用逗号分隔
  41. ## Constraint
  42. ## Constraint
  43. 接下来来个稍微复杂点的例子:
  44. .play codes/stringfy.go /START OMIT/,/END OMIT/
  45. - T 可以是任意类型
  46. - 类型 T 可能并没有String方法
  47. **以上代码并不能运行**
  48. ## Constraint
  49. 在其他有泛型的语言中也会出现类似的情况。
  50. 例如,在C++中。
  51. 调用v.String()是允许的,在编译过程中,如果发现实际调用时传入的类型实参T没有String方法,那么会报错误,如果有String方法,可以正常编译。
  52. 也就是说:**C++实际上对类型是没有明确限制的**
  53. ## Constraint
  54. 出于语言风格考虑,Go语言不会采用上述方案。
  55. - 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.
  56. - Another reason is that Go is designed to support programming at scale.
  57. Details see: [Type Parameters Proposal # Constraint](https://go.googlesource.com/proposal/+/refs/heads/master/design/43651-type-parameters.md#constraints)
  58. 通常,我们希望泛型代码中的类型参数满足一定的条件,这些条件被称为约束(Constraints)。
  59. Constraints必须能够同时限制调用方传入的类型参数以及泛型函数的具体实现:
  60. 1. **调用泛型函数时传入的类型实参必须满足Constraints**
  61. 2. **实现泛型函数时必须用Constraints允许的方式来使用这些值(e. g. + - * / > ....)**
  62. ## Constraint
  63. 首先看一个特殊的constraint:**any**,表示类型参数允许是任何类型。any约束下各类型(T)允许的操作有:
  64. - 申明对应类型的变量
  65. - 给此类型变量重新赋一个相同类型的值
  66. - 将此类型变量传给其他函数或者作为返回值返回
  67. - 取此类型变量的地址
  68. - 强制类型转换为interface{}类型或者赋值给interface{}类型的变量
  69. - 将类型T强转为类型T(允许但是没啥用)
  70. - 使用类型断言将interface转换为类型T
  71. - 在type switch中使用此类型作为其中一个case
  72. - 定义及使用此类型的复合类型(例如切片)
  73. - 将此类型作为预定义类型的参数,比如new函数
  74. ## Constraint