高階函數 - Higher order functions
Swift作為一門多范式編程語言,尤其是對函數式編程的支持,成就了Swift對高階函數的無障礙運用。
高階函數僅僅只是一個函數,其可以接收函數作為參數,或者返回一個函數來操作其他函數。Swift的集合類型中就有這些高階函數:Map, FlatMap, Filter, 和Reduce。
Map
對集合進行循環,并對集合中的每個元素采取相同的操作。
為了更簡單的介紹這個函數,假設我們有一個需求:將[1, 2, 3]
轉換為["1", "2", "3"]
,一般情況下我們會這么做:
var numbers = [1, 2, 3]
var strings: [String] = []
for number in numbers {
strings.append("\(number)")
}
print(strings)
如果我們使用Map函數:
var numbers = [1, 2, 3]
var stringsUseMap1 = numbers.map({(value: Int) -> String in
return String(value)
})
//stringsUseMap1 = ["1", "2", "3"]
var stringsUseMap2 = numbers.map{(value: Int) in
return String(value)
}
//stringsUseMap2 = ["1", "2", "3"]
var stringsUseMap3 = numbers.map{ value in String(value) }
//stringsUseMap3 = ["1", "2", "3"]
var stringsUseMap4 = numbers.map{ String($0) }
//stringsUseMap4 = ["1", "2", "3"]
以上四種Map函數的調用都是正確的,唯一的區別就是你喜歡使用長的還是喜歡使用短的。
在Swift中,如果閉包是函數的唯一參數或是其最后一個參數時,()可以被省略。
Swift 自動為內聯函數提供了參數名稱縮寫功能,您可以直接通過
$0
,$1
,$2
來順序調用閉包的參數。
如果您在閉包表達式中使用參數名稱縮寫,您可以在閉包參數列表中省略對其的定義,并且對應參數名稱縮寫的類型會通過函數類型進行推導。 in關鍵字也同樣可以被省略。上面例子中$0
為數組numbers
內部每一個元素的代表。
Filter
循環遍歷集合并返回包含滿足條件的元素的數組。
現在我們需要對數組中數字進行奇數和偶數的處理:
var numbersFilter = [1, 2, 3, 4, 5, 6, 7, 8]
//從數組中刪除所有奇數(即保留所有滿足條件的元素)
var evenNumbersFilter = numbersFilter.filter { $0 % 2 == 0 }
print(evenNumbersFilter)
//"[2, 4, 6, 8]\n"
//刪除所有偶數
var oddNumbersFilter = numbersFilter.filter { $0 % 2 == 1 }
print(oddNumbersFilter)
//"[1, 3, 5, 7]\n"
使用Filter函數簡單到無法形容!!!
Reduce
將集合中的所有項組合起來,以創建一個單一的值。
假設我們現在需要計算數組中數字的和:
var numbersReduce = [1, 2, 3, 4, 5]
var sum = numbersReduce.reduce(0) { $0 + $1 } // 15
上例等同于0+1+2+3+4+5, 0是一個初始值,$0是前兩個值的和(即0,1,...),$1(1,2,3,4,5)是數組的下一個值。
或者簡化為:
var numbersReduce = [1, 2, 3, 4, 5]
var sumReduce = numbersReduce.reduce(0, +) // 15
Reduce接受兩個參數,一個初始值,一個用于合并數組元素的閉包。為Reduce提供的閉包中有兩個參數,第一個是部分結果,第二個是來自數組的一個元素。閉包會針對每個元素進行逐次調用。
或者將字符串數組中的字符串進行合并:
var combineStrings = ["oh","captain",",","my","captain"].reduce(""){$0 + $1};
//combineStrings = ohcaptain,mycaptain
FlatMap
當在序列上實現時:對集合的集合進行平化。
假設我們現在有一個數組,其元素是兩個數組,每個數組內的元素是一些數字,我們需要將這些數字放到一個數組中:
var arrayInArray = [[1,2,3],[6,7,8]]
var flattenedArray = arrayInArray.flatMap{$0}
//flattenedArray = [1, 2, 3, 6, 7, 8]
簡單到窒息??!
鏈式調用
let animals = ["cat", "dog", "turtle", "swift", "elephant"]
let listAnimals = animals
.filter {$0 != "dog"}
.map {"\($0) "}
.reduce("") { $0 + $1 }
print(listAnimals)
上例中:首先創建一個數組,然后對數組animals調用高階函數filter,filter尾隨閉包內部的條件,幫助我們去除了animals中的字符串dog并生成了一個數組["cat", "turtle", "swift", "elephant"],然后對這個新生成的數組調用高階函數map,生成一個每個元素都包含一個空格的數組["cat ", "turtle ", "swift ", "elephant "],最后再對這個新數組執行reduce函數,初始值接受一個空字符串,尾隨閉包執行合并數組中元素的操作,最終,listAnimals的結果是“cat turtle swift elephant ”
學習這些高階函數有什么意義?
- 閱讀和理解復雜的函數式編程
- 編寫更優美、更易于維護的代碼,具有更好的可讀性
- 提高我們的Swift語言能力