Swift4 中的泛型約束
源連結:http://www.cocoachina.com/ios/20171025/20903.html
範型可以說是 Swift 跟 OC 相比最大的優勢了。通過給像集合這類東西關聯泛型, 可以寫出更可預測並且更安全的程式碼。在 Swift4 中型別約束更為強大, 它能夠讓我們更能夠輕而易舉的做很多事情。即使是通用程式碼, 也能充分的利用 Swift 的型別系統。
例1:
首先我們來看看一個簡單的例子。比如說給一個數字數字求和。我們可能會些這樣的程式碼:
123456 | // 在這段程式碼中, 我們定義了一個方法, 接受一個 Int 陣列作為引數, 在方法內部使用高階函式 reduce 最後返回這個結果。 func sum(_ numbers: [Int]) -> Int { return numbers.reduce( 0 , +) } let array = [ 1 , 2 , 3 , 4 , 5 ] sum(array) // 15 |
使用泛型約束, 我們可以這樣來實現這個需求:
1234567 | // 在這段程式碼中, 我們給 Array 添加了型別約束的 Extension。當陣列的 Element 遵守了 Numeric 協議的時候, Array 就擁有 sum 這個方法。 extension Array where Element: Numeric { func sum() -> Element { return reduce( 0 , +) } } array.sum() // 15 |
兩者相比, 使用泛型約束最大的優勢是使用擴充套件, 能夠讓這個功能跟呼叫者更緊密。比較一下:
12 | let sum = sum(array) let sum = array.sum() |
在 OC 裡面, 可能有些同學會寫一個 XXXTool 之類的類, 來封裝這種型別的功能。 或者是直接寫成 C 的函式。但是不論怎麼寫, 這樣貌似都不是特別的 OOP。或者OC 還可以直接給 NSArray 加一個 category, 然後再實現相似的功能。但是, 這樣做不就等於所有的 array 都具有這個功能了嗎?
例2
再來看這樣的需求: 計算某個包含字串集合中有多少個單詞。我們可以通過給集合新增一個擴充套件輕鬆的完成這件事情。給 Collection 新增一個約束, 限制集合中的 Element 是 String型別:
12345678910 | extension Collection where Element == String { func countWords() -> Int { return reduce( 0 ) { let components = $ 1 .components(separatedBy: .whitespacesAndNewlines) return $ 0 + components.count } } } let array2 = [ "sunny" , "cloudy" , "apple orange" ] array2.countWords() // 4 |
還有一個很酷的做法是約束集合型別中的 Element 是 Closure:
123456789101112131415 | extension Sequence where Element == () -> Void { func callAll() { forEach { $ 0 () } } } let closure1 = { print( "1" ) } let closure2 = { print( "2" ) } let array3 = [closure1, closure2] array3.callAll() //1 //2 |
例3
還有一個很好用的特性是使用協議定義 API 的時候。這幾乎是寫可測試程式碼以及功能解耦的最佳實踐了。需要注意的是, 在需要靈活使用巢狀型別的時候, 這可能會有點麻煩。
看例子吧!我們經常都想要定義一些通用的 API, 來管理程式中的各種 model。這時候肯定會想要定義一個協議:
123 |
|