記錄一下Swift中的map和flatMap。git
網上不少文章都是以前的,那時flatMap的定義還有兩個重載的函數,對應的源碼也是以前版本的~所以我在沒看源碼前,對flatMap的實現有了一些誤解。由下面這段代碼的輸出引起的本次探索。github
let arr = [1, 2, 3]
print(arr.map{"NO.\($0)"})
print(arr.flatMap{"NO.\($0)"})
複製代碼
先貼源碼swift
@inlinable
public func map<T>(
_ transform: (Element) throws -> T
) rethrows -> [T] {
let initialCapacity = underestimatedCount
var result = ContiguousArray<T>()
result.reserveCapacity(initialCapacity)
var iterator = self.makeIterator()
// Add elements up to the initial capacity without checking for regrowth.
for _ in 0..<initialCapacity {
result.append(try transform(iterator.next()!))
}
// Add remaining elements, if any.
while let element = iterator.next() {
result.append(try transform(element))
}
return Array(result)
}
複製代碼
這段源碼和網上大多文章同樣,map裏面的處理以下。api
結合咱們從Xcode中看到的解釋以及源碼,咱們能夠知道flatMap就是返回的Array(s.map(transform).joined())數組
public func flatMap<SegmentOfResult>(
_ transform: @escaping (Elements.Element) -> SegmentOfResult
) -> LazySequence<
FlattenSequence<LazyMapSequence<Elements, SegmentOfResult>>> {
return self.map(transform).joined()
}
複製代碼
因此,以前的實現方法appendContents那種都無效了。所以開頭那個demo輸出也和以前不同了(按以前的實現,flatMap輸出的和map同樣),結果以下。bash
["NO.1", "NO.2", "NO.3"]
["N", "O", ".", "1", "N", "O", ".", "2", "N", "O", ".", "3"]
複製代碼
用flatMap的時候,結果返回有可選值的時候,好比對數組裏面的字符串轉成Int,Xcode會提示咱們用compactMap方法。 閉包
我是看的唐巧大神的文章Swift 燒腦體操(四) - map 和 flatMapapp
本身也整理了一下。 源碼地址函數
@inlinable
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
}
}
@inlinable
public func flatMap<U>(
_ transform: (Wrapped) throws -> U?
) rethrows -> U? {
switch self {
case .some(let y):
return try transform(y)
case .none:
return .none
}
}
複製代碼
這段代碼,乍一看相同,不一樣之處在於:ui
因此map有可能形成多重Optional的問題,Optional嵌套可看唐巧大神的文章 https://blog.devtang.com/2016/02/27/swift-gym-1-nested-optional/。