一、Optional的map和flatMap
Optional 的定义
public enum Optional<Wrapped> : ExpressibleByNilLiteral {
//我们在��写代码的时候,习惯用 nil 来表示空值,而不是 .none
case none
//非空的值用 Wrapped 来表示
case some(Wrapped)
//optional只有一个map函数,无�其它变体
public func map<U>(_ transform: (Wrapped) throws -> U) rethrows -> U? {
switch self {
case .some(let y):
return .some(try transform(y))
case .none:
return .none
}
}
//optional只有一个flatMap函数,无�其它变体
public func flatMap<U>(_ transform: (Wrapped) throws -> U?) rethrows -> U?{
switch self {
case .some(let y):
return try transform(y)
case .none:
return .none
}
}
map 和 flatMap的共性
map和flatMap函数的返回结果依旧是可选性
;但返回的可选值类型可以与原可选值类型不一致。
- 如果�原optional没有值, map和flatMap函数都直接�返回nil。
- flatMap�:如果原optional有值�非空,则用解包后的值y做参数来�调用闭包transform,闭包的结果�就是flatMap的结果,
transform(y)�
���降维。 - map:如果原optional有值�非空,则用解包后的值y做参数来�调用闭包transform,map的返回值是
.some( transform(y) )
例如:
// flatMap降维和 map的对比示例
let a: String? = "1"
let am = a.map{ Int($0) } // 闭包结果类型 Int?
print( am ) // Optional(Optional(1)) map结果类型 Int?? .some( transform(y) )
let afm = a.flatMap{ Int($0) } // 闭包结果类型 Int?
print(afm) // Optional(1) flatMap结果类型 Int?? transform(y)�
// 原来类型:Int?, 返回值类型:String?
let b: Int? = 1
let bm = b.map { String("result = \($0)") } // 闭包结果类型 String
print(bm) /// "Optional("result = 1")"
// 原optional没有值, map和flatMap函数都直接�返回nil
let c:Int? = nil
let cm = c.map { String("result = \($0)") } // 闭包结果类型 String
print(bm) /// "nil" map结果类型 String?
结论:那什么时候使用flatMap 方法呢?答案是:当我们的闭包transform(y)的��返回值�是可选型的��时候,可以用f�latMap来降一次维
。
二、Sequence 的� flatMap: 去空降维
每调用一次flatMap就去一次空、或降一次维
- 去空:把空值nil过滤掉。
- 降维:比如把�二维数组压平成一维数组。
- 每次调用只能2选一(去空、或降维),�这2个功能各自对应一个不同的重载flatMap函数。
extension SequenceType {
// 去空:把空值nil过滤。
public func flatMap<T>(transform: (Self.Generator.Element) -> T?) -> [T]
// 降维:比如把二维数组压平成一维数组
public func flatMap<S : SequenceType>(transform: (Self.Generator.Element) -> S) -> [S.Generator.Element]
// [Int?] -> [ Int ] 去空
var a = [1, 3, 5, nil, 7, 9] // a 类型 [Int?]
let afm = a.flatMap{ $0 } // afm 类型是 [ Int ]
print(type(of: afm), ": ", afm) /// [1, 3, 5, 7, 9]
// [ [Int] ] -> [ Int ] 降维
var b = [[1, 3, 5], [7, 9] ] // b 类型 [ [Int] ]
let bfm = b.flatMap{ $0 } // bfm 类型 [ Int ]
print(type(of: bfm),": ", bfm) /// [1, 3, 5, 7, 9 ]
// [ [Int]? ] -> [ [Int] ] 去空
var c = [ [1, 3, 5], [7, 9], nil ] // c 的类型是 [ [Int]? ]
let cfm = c.flatMap{ $0 } // cfm 类型 [ [Int] ]
print(type(of: cfm),": ", cfm) /// [[1, 3, 5], [7, 9] ]
// [ [Int?] ] -> [ Int? ] 降维
var d = [ [1, 3, 5], [7, 9], [nil] ] // c 的类型是 [ [Int?] ]
let dfm = d.flatMap{ $0 } // dfm 类型 [ Int? ]
print(type(of: dfm),": ", dfm) /// [1, 3, 5, 7, 9, nil ]
// [ [Int?]? ] -> [ [Int?] ] 去空
var e = [ [1, 3, 5], [7, 9], [nil], nil ] // c 的类型是 [ [Int?]? ]
let efm = e.flatMap{ $0 } // efm 类型 [ [Int?] ]
print(efm) /// [[1, 3, 5], [7, 9], [nil], [10] ]
结论: 最好在操作 flatMap 时, 最好显示声明类型
,这样可以更清晰的知道应该调用多少次flatMap,如:
// [ [Int?]? ] -> [ Int ] 一看就知道要调用3次。
var f: [ [Int?]? ] = [ [1, 3, 5], [7, 9], [nil], nil ] // c 的类型是 [ [Int?]? ]
let ffm3: [ Int ] = f.flatMap{ $0 }.flatMap{ $0 }.flatMap{ $0 } // efm 类型 [ Int ]
print(ffm3) /// [1, 3, 5, 7, 9]