Swift-泛型
参考:
Swift 的 Array
和 Dictionary
都是泛型集合
泛型函数
如下的函数pairsFromDictionary
:
func pairsFromDictionary<KeyType,ValueType>(dictionary: [KeyType: ValueType]) -> [(KeyType,ValueType)] { return Array(dictionary) }
使用情况如下:
let pairs = pairsFromDictionary(["minimum": 199,"maximum": 299]) let morePairs = pairsFromDictionary([1: "Swift",2: "Generics",3: "Rule"])
使用泛型来定义栈和队列
栈
struct Stack<Element> { var items = [Element]() mutating func push(item: Element) { items.append(item) } mutating func pop() -> Element { return items.removeLast() } }
方法被标记为 mutating
,因为它们需要修改结构体的 items
数组
队列
struct Queue<Element> { private var elements = [Element]() mutating func enqueue(newElement: Element){ elements.append(newElement) } mutating func dequeue() -> Element? { guard !elements.isEmpty else { return nil } return elements.removeAtIndex(0) } func peek() -> Element? { return elements.first } }
类型约束
类型约束可以指定一个类型参数必须继承自指定类,或者符合一个特定的协议或协议组合。
例如,Swift 的 Dictionary
类型对字典的键的类型做了些限制。在字典的描述中,字典的键的类型必须是可哈希(hashable
)的。也就是说,必须有一种方法能够唯一地表示它。Dictionary
的键之所以要是可哈希的,是为了便于检查字典是否已经包含某个特定键的值。若没有这个要求,Dictionary
将无法判断是否可以插入或者替换某个指定键的值,也不能查找到已经存储在字典中的指定键的值。
如下,在数组中查找是否有需要查找的值:
func findIndex<T>(array: [T],_ valueToFind: T) -> Int? { for (index,value) in array.enumerate() { if value == valueToFind { return index } } return nil }
但是,这个函数无法通过编译,原因是不是所有的 Swift 类型都可以用等式符(==
)进行比较。
Swift 标准库中定义了一个 Equatable
协议,该协议要求任何遵循该协议的类型必须实现等式符(==
)及不等符(!=
),从而能对该类型的任意两个值进行比较。所有的 Swift 标准类型自动支持 Equatable
协议。
func findIndex<T: Equatable>(array: [T],value) in array.enumerate() { if value == valueToFind { return index } } return nil }
也可使用where
来约束类型:
func mid<T where T: Comparable>(array: [T]) -> T { return array.sort()[(array.count - 1) / 2] }
sort()
要可用,需要array遵循Comparable
协议。
等同于:
func mid<T: Comparable>(array: [T]) -> T { return array.sort()[(array.count - 1) / 2] }
继承泛型类
例如有如下的泛型类:
class Box<T> { }
有如下的两种继承方式:
class Gift<T>: Box<T> { } class StringBox: Box<String> { }
Enums With Multiple Generic Associated Values
如下的泛型enum有两个关联的值:一个用来表示实际的结果,一个用来表示可能的错误。
enum Result<ValueType,ErrorType> { case Success(ValueType) case Failure(ErrorType) }
使用情况如下:
func divideOrError(x: Int,y: Int) -> Result<Int,String> { guard y != 0 else { return Result.Failure("Division by zero is undefined") } return Result.Success(x / y) }