https://developer.apple.com/library/prerelease/content/documentation/Swift/Conceptual/Swift_Programming_Language/Generics.html#//apple_ref/doc/uid/TP40014097-CH26-ID179
Swift的Generics其实就是泛型, 而且语法和作用跟Java很像。 Swift的三种集合类型Set、Array和Dictionary都使用泛型声明成员参数类型, 跟Java的Set、List和Map类似。
附Swift的定义:
public struct Set<Element : Hashable> : SetAlgebra, Hashable, Collection, ExpressibleByArrayLiteral
说明:Set是结构体,数据类型Element必须实现了Hashable接口。
public struct Array<Element> : RandomAccessCollection, MutableCollection
说明:Array是结构体, 数据类型是泛型Element。
public struct Dictionary<Key : Hashable, Value> : Collection, ExpressibleByDictionaryLiteral
说明:Dictionary是结构体, 2个参数都是泛型。第一个参数类型Key实现了Hashable接口, 第二个参数类型是Value。 这里的Key和Value都是数据类型。
苹果用了一个例子解释泛型的用处, 即交换2个参数的值(PS:如果懂得其它语法的泛型,这个例子可以跳过。)
1、交换2个整型变量的值,在以前博文中有该示例代码:
func swapTwoInts(_ a: inout Int, _ b: inout Int) { //如果要修改值必须添加inout关键字,表示是引用
let temporaryA = a
a = b
b = temporaryA
}
var someInt = 3
var anotherInt = 107
swapTwoInts(&someInt, &anotherInt) //注意参数前添加&符号,表示引用
someInt等于107,anotherInt等于3
func swapTwoStrings(_ a: inout String, _ b: inout String) {
let temporaryA = a
a = b
b = temporaryA
}
func swapTwoDoubles(_ a: inout Double, _ b: inout Double) {
let temporaryA = a
a = b
b = temporaryA
}
从上面3个示例代码可以看出只有函数参数类型不同, 函数体是一模一样的。 使用泛型的参数类型,一个函数就能实现交换2个值的功能。 跟Java一样, Swift泛型使用尖括号<T>。
func swapTwoValues<T>(_ a: inout T, _ b: inout T) {
let temporaryA = a
a = b
b = temporaryA
}
var someInt = 3
var anotherInt = 107
swapTwoValues(&someInt, &anotherInt)
// someInt is now 107, and anotherInt is now 3
var someString = "hello"
var anotherString = "world"
swapTwoValues(&someString, &anotherString)
// someString is now "world", and anotherString
注意:参数一定添加&前缀,表示它是引用传递。
PS: Swift对泛型的命名没有限制, 由一个或若干个英文字符组成。 合法命名示例:<T>, <T, V>, <Element>, <AAA>, <TypeC>等等。
Swift同样支持protocol即接口使用泛型, 就像Java的interface使用泛型一样。使用associatedtype关键字作为泛型的前缀。示例代码如下:
public interface ICallback<T> {
int getCount(T param);
}
上面是个最简单的Java接口类, 函数getCount的参数是泛型T。
protocol ICallBack {
associatedtype T //assciatedtype表示T是一个泛型
func getCount(_ param: T) -> Int
}
上面是Swift的写法, 跟Java代码的功能完全一样。
泛型也支持用where关键字添加限制条件, 下面示例代码使用==判断泛型是否相同; 用法跟SQL有点像。 在调用allItemsMatch函数时必须保证参数类型符合where条件。
protocol Container {
associatedtype ItemType
mutating func append(_ item: ItemType)
var count: Int { get }
subscript(i: Int) -> ItemType { get }
}
func allItemsMatch<C1: Container, C2: Container>
(_ someContainer: C1, _ anotherContainer: C2) -> Bool
where C1.ItemType == C2.ItemType, C1.ItemType: Equatable {
...
}
1、泛型C1必须实现了Container, C2实现了Container。
2、someContainer是C1类型的;
3、anotherContainer是C2类型的;
4、函数返回值是布尔类型的;
5、在函数返回值后面可以添加where判断语句,用于判断类型C1和C2的ItemType是否一样, 而且ItemType实现了Equatable。
Swift的泛型语法跟Java泛型很像, 就不按照苹果原文翻译举例了。 总结一个Swift Generic的特性:
1、 基本语法是在类、结构体、枚举、函数名称后面跟着<>和字符串, 可以有一个或者多个数据类型;
2、泛型可以添加限制条件,即实现了几个接口Protocol; 语法是<T: Type>。
3、protocol在使用泛型时要添加成员变量, 并使用associated type关键字。
4、在函数里使用泛型时可以使用where关键字限制各个参数类型的关系。