仓颉开发之——泛型(10)

一 概述

  • 泛型概述
  • 泛型函数
  • 泛型接口
  • 泛型类
  • 泛型结构体
  • 泛型枚举
  • 类型别名
  • 泛型约束

二 泛型概述

2.1 什么是泛型

  • 泛型指的是参数化类型,参数化类型是一个在声明时未知并且需要在使用时指定的类型
  • 类型声明与函数声明可以是泛型的
  • 最为常见的例子就是 Array<T>、Set<T> 等容器类型

2.1.1 几个常用术语

1
2
3
4
5
6
class List<T> {
var elem: Option<T> = None
var tail: Option<List<T>> = None
}

func sumInt(a: List<Int64>) { }

说明:

  • 类型形参:List<T> 中的 T
  • 类型变元: elem: Option<T> 中对 T 的引用
  • 类型实参: sumInt 的参数中 List<Int64> 的 Int64
  • 类型构造器:func sumInt(a: List<Int64>)中List就是类型构造器

三 泛型函数

3.1 泛型函数概念

  • 一个函数声明了一个或多个类型形参,则将其称为泛型函数
  • 类型形参紧跟在函数名后,并用 <> 括起,有多个类型形参用“,”分离。

3.2 全局泛型函数

1
2
3
func id<T>(a: T): T {
return a
}

说明:

  • 在函数名后使用尖括号声明类型形参,然可以在函数形参、返回类型及函数体中对其进行引用
  • 泛型函数 composition func composition<T1, T2, T3>(f: (T1) -> T2, g: (T2) -> T3): (T1) -> T3{} 声明了 3 个类型形参,分别是 T1, T2, T3,其功能是把两个函数 f: (T1) -> T2, g: (T2) -> T3 复合成类型为 (T1) -> T3 的函数。

3.3 局部泛型函数

1
2
3
4
5
6
7
8
9
10
11
12
func foo(a: Int64) {
func id<T>(a: T): T { a }

func double(a: Int64): Int64 { a + a }

return (id<Int64> ~> double)(a) == (double ~> id<Int64>)(a)
}

main() {
println(foo(1))
return 0
}

说明:

  • ~>是composition 函数,是两个函数的复合
  • 根据推测和结果可知:函数 id<Int64> ~> double 和 double ~> id<Int64> 是等价的

3.4 泛型成员函数

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
class A {
func foo<T>(a: T): Unit where T <: ToString {
println("${a}")
}
}

struct B {
func bar<T>(a: T): Unit where T <: ToString {
println("${a}")
}
}

enum C {
| X | Y

func coo<T>(a: T): Unit where T <: ToString {
println("${a}")
}
}

main() {
var a = A()
var b = B()
var c = C.X
a.foo<Int64>(10)
b.bar<String>("abc")
c.coo<Bool>(false)
return 0
}

说明:

  • class、struct 与 enum 的成员函数可以是泛型的
  • class 中声明的泛型成员函数不能被 open 修饰,如果被 open 修饰则会报错

4.4 静态泛型函数

1
2
3
4
5
6
7
8
9
10
11
12
13
import std.collection.*

class ToPair {
public static func fromArray<T>(l: ArrayList<T>): (T, T) {
return (l[0], l[1])
}
}

main() {
var res: ArrayList<Int64> = ArrayList([1,2,3,4])
var a: (Int64, Int64) = ToPair.fromArray<Int64>(res)
return 0
}

五 泛型接口

1
2
3
public interface Iterable<E> {
func iterator(): Iterator<E>
}

说明:接口interface中的泛型

六 泛型类

1
2
3
4
5
6
7
8
9
10
11
public open class Node<K, V> where K <: Hashable & Equatable<K> {
public var key: Option<K> = Option<K>.None
public var value: Option<V> = Option<V>.None

public init() {}

public init(key: K, value: V) {
this.key = Option<K>.Some(key)
this.value = Option<V>.Some(value)
}
}

说明:class中的泛型

七 泛型结构体

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
struct Pair<T, U> {
let x: T
let y: U
public init(a: T, b: U) {
x = a
y = b
}
public func first(): T {
return x
}
public func second(): U {
return y
}
}

main() {
var a: Pair<String, Int64> = Pair<String, Int64>("hello", 0)
println(a.first())
println(a.second())
}

说明:struct结构体中的泛型

八 泛型枚举

1
2
3
4
5
6
7
8
9
10
11
12
13
14
package core // `Option` is defined in core.

public enum Option<T> {
Some(T)
| None

public func getOrThrow(): T {
match (this) {
case Some(v) => v
case None => throw NoneValueException()
}
}
...
}

说明:enum枚举中的泛型

九 类型别名

1
type I64 = Int64

说明:

  • 使用type为此类型设置一个别名
  • type +别名+ = 最后是原类型
  • 只能在源文件顶层定义类型别名

十 泛型约束

10.1 概念

  • 约束大致分为接口约束与子类型约束
  • 语法为在函数、类型的声明体之前使用 where 关键字来声明
  • 同一个类型变元的多个约束可以使用 & 连接

10.2 示例

1
2
3
4
5
6
7
8
func genericPrint<T>(a: T) where T <: ToString {
println(a)
}

main() {
genericPrint<(Int64) -> Int64>({ i => 0 })
return 0
}

十一 思维导图

十二 参考

  • 仓颉官方文档—泛型
  • 仓颉编程语言入门教程