Swift基础学习<十九>:泛型-节点泛型

深渊向深渊呼唤

泛型:泛型代码可以确保写出灵活的,可重用的函数。

节点泛型:在 Swift 中,有参数的函数必须指定参数的类型,现在有几个同名的函数实现相似的功能,但是参数的类型不同,例如:

Func show (para:Int) { print(“Hello (para)”) }

Func show (para:String) { print(“Hello (para)”) } …

虽然系统可以根据参数类型调用不同的参数,但在定义上这种方法太过冗余。泛型所带来的好处就是我们可以通过定义单个函数来实现上面的功能。使用泛型作为参数的函数叫做泛型函数,下面是与上例有相同功能的泛型函数定义:

func show<T>(para:T) {
	print(“Hello \(para)”)
}

我们可以给这个泛型函数传入不同类型的值:

show(“小明”) //输出 “Hello小明”
show(12). //输出 “Hello 12”

泛型函数在声明时使用了节点类型命名(通常情况下用字母 T、U、V 这样的大写字母来表示)类代替实际类型名 (如 Int 、String 或 Double)。 节点类型在定义时不表示任何具体类型,在函数被调用时会根据传入的实际类型来指定自身的类型。另外需要指出的是,如果函数的泛型列表中只有一个 T, 虽然具体类型不需要指定,但是每个节点类型的参数必须是相同类型的。例如,有一个如下定义的函数:

func show<T>(para1:T , para2:T ) {…}

在调用这个函数时,两个参数必须是相同的类型:

show(1,2) //Int 类型
show(“小明”,”小刚”) //String类型。

如果要定义多个不同类型的泛型,则需要在尖括号中加入多个节点: <T,U,V …>,在泛型函数名后面插入节点的声明。 声明会告诉Swift,尖括号中的T是 show 函数所定义的一个节点类型。因为 T 是一个节点,所以Swift不会去查找是否有一个命名为T的实际类型。 你可以对节点进行一些限制,比如要求泛型遵守某些协议,Swift中数组的判等就是这样定义的:

public func == <Element: Equatable>(1hs:[Element], rhs:[Element]) -> Bool

Element 是使用节点声明的,它代表一个泛型,可以看到这里的泛型名是 Element, 相比上面的 T, U ,V 要长得多。这是因为此处的 Element 不仅仅是一个占位符的作用,它还声明了这个泛型代表数组中的元素类型,有具体的意义,这种API的设计原则值得我们借鉴。有时候节点中的泛型需要有更多的限制,需要使用 where子句来补充约束条件:
func anyCommonElements <T: SequenceType , U : SequenceType where 
	T.Generator.Element:Equatable,
	T.Generator.Element == U.Generator.Element>(1hs:T, _ rhs: U) -> Bool { … }

Swift 3.0 中 where子句被移动到了参数列表的后面,这是因为相比于 where.子句,参数列表的优先级更高,较长的 where 子句,参数列表的优先级更高,较长的 where子句会影响参数列表的阅读,所以 Swift 3.0 的格式如下:

func anyCommonElements<T: SequenceType, U : SequenceType> (1hs: T, _ rhs: U) -> Bool 
where 
	T.Generator.Element : Equatable,
	T.Generator.Element == U.Generator.Element { … }
栏目