通用代码使您能够根据您定义的要求编写可以使用任何类型的灵活,可重用的函数和类型。您可以编写避免重复的代码,并以清晰,抽象的方式表达其意图。
泛型是Swift最强大的功能之一,Swift标准库的大部分内容都是使用通用代码构建的。
import Foundation
//泛型函数
func swapTwoValues<T>(_ a: inout T, _ b: inout T) {
let tmp = a
a = b
b = tmp
}
var a = 1, b = 2
print("\(a)====\(b)")
swapTwoValues(&a, &b)
print("\(a)====\(b)")
//泛型类型(泛型类,泛型结构体,泛型枚举),听起来挺高大上,其实就是给自定义类加个泛型
struct Stack<Element> {
var items: [Element] = []
mutating func push(_ item: Element) {
items.append(item)
}
mutating func pop() -> Element {
return items.removeLast()
}
}
//扩展泛型类型
extension Stack {
var topItem: Element? {
return items.isEmpty ? nil : items[items.count - 1]
}
}
var strings = Stack<String>()
strings.push("hello")
print(strings.topItem)
print(strings.pop())
//泛型约束(不限于泛型类型,除了泛型类型就是TM的泛型函数)
//泛型约束不能省略,如果省略value == v就不能运行了,没法玩了.
//泛型约束必须是特定类继承,或符合特定协议或协议组合
//这里Equable不能被替换为String,因为String是结构体,不能被继承.Int, Bool, Double, anything else...
//返回值不能用泛型,🙂because the type to use for T is inferred from the types of values passed to the function.
// (因为类型都是从传递给函数的值的类型推断出来的),除非再传一个参数,类似:
// func findIndex1<T: Equatable, S: SignedInteger>(of value: T,in array: [T], _ type: S) -> S?
// 告诉一下Swift,接下来会发生什么,不然Swift心里会发慌...
func findIndex1<T: Equatable>(of value: T,in array: [T]) -> Int? {
for (i, v) in array.enumerated() {
if value == v {
return i
}
}
return nil
}
let arr = ["a", "b", "c", "d", "e"]
let index = findIndex1(of: "a", in: arr)
print(index)
//关联类型
//协议中的泛型,实现具体类型的时候,由自己指定泛型类型为某种具体类型.
protocol Container {
associatedtype Item
mutating func append(_ item: Item)
var count: Int { get }
subscript(i: Int) -> Item { get }
}
//这里typealias item不能等于协议,例如typealias Item = Equatable
//这样Swift就不知道`EquableStack`应该怎么分配内存了有木有...,谁TM知道`EquableStack`实现了几个协议
//脚踏了几只船?
//typealias Item = Int删掉也可以,可以通过append,推断出Item类型
struct IntStack: Container {
mutating func push(_ item: Item) {
items.append(item)
}
mutating func pop() -> Item {
return items.removeLast()
}
typealias Item = Int
var items: [Item] = []
mutating func append(_ item: Item) {
items.append(item)
}
var count: Int {
return items.count
}
subscript(i: Int) -> Item {
return items[i]
}
}
//上面的Stack可以写作下面方式
//因为通过append可以知道Element为Item的具体类型,所以typealias可以省略
//又因为Stack1是泛型类型,Element创建实例对象时具体指出,所以,一下代码完全正确.
//可以写typealias Item = Element, 然后Element跟Item可以互相交叉替换🙂
struct Stack1<Element>: Container {
var items = [Element]()
mutating func push(_ item: Element) {
items.append(item)
}
mutating func pop() -> Element {
return items.removeLast()
}
//conformance to the Container
mutating func append(_ item: Element) {
push(item)
}
var count: Int {
return items.count
}
subscript(i: Int) -> Element {
return items[i]
}
}
var strings1 = Stack1<String>()
strings.push("hello")
print(strings.topItem)
print(strings.pop())
//扩展现有类型以指定关联类型
//array 中有append用来推断具体类型,并且有count,有下标
//所以以后完全可以使用Array作为Container
//但是typealias Container = Array也是不错的
extension Array: Container {}
//将约束添加到关联类型
//如果这样定义,得像下面这样搞
//struct Stack1<Element: Equatable>: Container
protocol Container1 {
associatedtype Item: Equatable
mutating func append(_ item: Item)
var count: Int { get }
subscript(i: Int) -> Item { get }
}
//在关联类型的约束中使用协议
//这个JB关系有点乱,有木有...
//儿子有一个家,爹有一个家,儿子从爹那继承过来的家跟自己成立的家必须是一个家,不能搞分家...
//大概就是这样了....
protocol SuffixableContainer: Container {
associatedtype Suffix: SuffixableContainer where Suffix.Item == Item
func suffix(_ size: Int) -> Suffix
}
extension Stack1: SuffixableContainer {
func suffix(_ size: Int) -> Stack1 {
var result = Stack1()
//max是用来防止程序崩溃的,🙂
for index in max((count-size), 0)..<count {
result.append(self[index])
}
return result
}
// Inferred that Suffix is Stack.
}
var stackOfInts = Stack1<Int>()
stackOfInts.append(10)
stackOfInts.append(20)
stackOfInts.append(30)
let suffix = stackOfInts.suffix(3)
//Generic Where Clauses(通用条款)
//泛型条件约束吧... where
func allItemsMatch<C1: Container, C2: Container>(_ someContainer: C1, _ anotherContainer: C2) -> Bool where C1.Item == C2.Item, C1.Item: Equatable {
// Check that both containers contain the same number of items.
if someContainer.count != anotherContainer.count {
return false
}
// Check each pair of items to see if they're equivalent.
for i in 0..<someContainer.count {
if someContainer[i] != anotherContainer[i] {
return false
}
}
// All items match, so return true.
return true
}
var stackOfStrings = Stack1<String>()
stackOfStrings.push("uno")
stackOfStrings.push("dos")
stackOfStrings.push("tres")
var arrayOfStrings = ["uno", "dos", "tres"]
if allItemsMatch(stackOfStrings, arrayOfStrings) {
print("All items match.")
} else {
print("Not all items match.")
}
extension Stack1 where Element: Equatable {
func isTop(_ item: Element) -> Bool {
guard let last = items.last else {
return false
}
return item == last
}
}
//如果将没有遵守Equatable用于该方法,会报错
if stackOfStrings.isTop("tres") {
print("Top element is tres.")
} else {
print("Top element is something else.")
}
//上面where扩展类型,下面where扩展协议,这TM就比较6了...
extension Container where Item: Equatable {
func startsWith(_ item: Item) -> Bool {
return count >= 1 && self[0] == item
}
}
if [9, 9, 9].startsWith(42) {
print("Starts with 42.")
} else {
print("Starts with something else.")
}
//Item是特定类型的where子句
extension Container where Item == Double {
func average() -> Double {
var sum = 0.0
for index in 0..<count {
sum += self[index]
}
return sum / Double(count)
}
}
print([1260.0, 1200.0, 98.6, 37.0].average())
//关联类型和泛型子句
protocol Container2 {
associatedtype Item
mutating func append(_ item: Item)
var count: Int { get }
subscript(i: Int) -> Item { get }
associatedtype Iterator: IteratorProtocol where Iterator.Element == Item
func makeIterator() -> Iterator
}
protocol ComparableContainer: Container2 where Item: Comparable {}
//泛型下标
extension Container2 {
subscript<Indices: Sequence>(indices: Indices) -> [Item]
where Indices.Iterator.Element == Int {
var result = [Item]()
for index in indices {
result.append(self[index])
}
return result
}
}
真是烧脑的玩意……
–EOF–