函数式Swift的知识点
@escaping 逃逸闭包
“当需要在函数返回之后使用其参数(如:region)时,该参数需要被标记为 @escaping。即使忘记标记,编译器也将会提醒我们。如果你想了解更详细的信息,请参阅 Apple 的 The Swift Programming Language 一书中《逃逸闭包》的部分。”
柯里化
形如 blur(radius: radius)(image)
参数的分别传入计算函数的, 这样的形式更易于函数的组合.
Map函数的实现
extension Array {
func map<T>(_ transform: (Element) -> T) -> [T] {
var result: [T] = []
for x in self {
result.append(transform(x))
}
return result
}
}
- 使用
func genericCompute<T>(array: [Int], transform: (Int) -> T) -> [T] {
return array.map(transform)
}
Filter函数的实现
extension Array {
func filter(_ includeElement: (Element) -> Bool) -> [Element] {
var result: [Element] = []
for x in self where includeElement(x) {
result.append(x)
}
return result
}
}
- 使用
func getSwiftFiles(in files: [String]) -> [String] {
return files.filter { file in file.hasSuffix(".swift") }
}
Reduce函数实现
- 一般的Reduce行为
func prettyPrint(strings: [String]) -> String {
var result: String = "Entries in the array xs:\n"
for string in strings {
result = " " + result + string + "\n"
}
return result
}
- 泛型实现
extension Array {
func reduce<T>(_ initial: T, combine: (T, Element) -> T) -> T {
var result = initial
for x in self {
result = combine(result, x)
}
return result
}
}
- 使用Reduce 实现 Map 和 Filter
extension Array {
func mapUsingReduce<T>(_ transform: (Element) -> T) -> [T] {
return reduce([]) { result, x in
return result + [transform(x)]
}
}
func filterUsingReduce(_ includeElement: (Element) -> Bool) -> [Element] {
return reduce([]) { result, x in
return includeElement(x) ? result + [x] : result
}
}
}
实际运用 Map Filter和Reduce
struct City {
let name: String
let population: Int
}
我们可以定义一些示例城市:
let paris = City(name: "Paris", population: 2241)
let madrid = City(name: "Madrid", population: 3165)
let amsterdam = City(name: "Amsterdam", population: 827)
let berlin = City(name: "Berlin", population: 3562)
let cities = [paris, madrid, amsterdam, berlin]
假设我们现在想筛选出居民数量至少一百万的城市,并打印一份这些城市的名字及总人口数的列表。我们可以定义一个辅助函数来换算居民数量:
extension City {
func scalingPopulation() -> City {
return City(name: name, population: population * 1000)
}
}
现在我们可以使用所有本章中见到的函数来编写下面的语句:
cities.filter { $0.population > 1000 }
.map { $0.scalingPopulation() }
.reduce("City: Population") { result, c in
return result + "\n" + "\(c.name): \(c.population)"
}
/*
City: Population
Paris: 2241000
Madrid: 3165000
Berlin: 3562000
*/
泛型和Any类型
泛型: 具备编辑器的类型检查, 使用泛型更具有通用性
Any: 则可以避开Swift的类型系统
可选值
let cities = ["Paris": 2241, "Madrid": 3165, "Amsterdam": 827, "Berlin": 3562]
可选绑定
if let madridPopulation = cities["Madrid"] {
print("The population of Madrid is \(madridPopulation * 1000)")
} else {
print("Unknown city: Madrid")
}
?? 运算符
默认值使用闭包, 可以避免不必要的计算
这里是运用的重点: 闭包的使用!!!
infix operator ??
func ??<T>(optional: T?, defaultValue: @autoclosure () throws -> T) rethrows -> T {
if let x = optional {
return x
} else {
return try defaultValue()
}
}
if 可选链
if let myState = order.person?.address?.state {
print("This order will be shipped to \(myState)")
} else {
print("Unknown person, address, or state.")
}
switch 的可选值
可以再case中使用 ? 解绑可选值
switch madridPopulation {
case 0?: print("Nobody in Madrid")
case (1..<1000)?: print("Less than a million in Madrid")
case let x?: print("\(x) people in Madrid")
case nil: print("We don't know about Madrid")
}
guard 的可选值
func populationDescription(for city: String) -> String? {
guard let population = cities[city] else { return nil }
return "The population of Madrid is \(population)"
}
可选映射 Optional.map
Optional 也提供了 map 函数, 可以对其解绑值进行处理
extension Optional {
func map<U>(_ transform: (Wrapped) -> U) -> U? {
guard let x = self else { return nil }
return transform(x)
}
}
func increment(optional: Int?) -> Int? {
return optional.map { $0 + 1 }
}
flatMap帮助解绑
其区别是和 map 的参数闭包的返回值类型 仍然是 可选类型
extension Optional {
func flatMap<U>(_ transform: (Wrapped) -> U?) -> U? {
guard let x = self else { return nil }
return transform(x)
}
}
extension Array{
func myFlatMap<T>(_ transform: (Element) -> [T]) -> [T] {
var tmp: [T] = []
for value in self {
tmp.append(contentsOf: transform(value));
}
return tmp;
}
}