Swift學習——map和flatMap

記錄一下Swift中的map和flatMap。git

網上不少文章都是以前的,那時flatMap的定義還有兩個重載的函數,對應的源碼也是以前版本的~所以我在沒看源碼前,對flatMap的實現有了一些誤解。由下面這段代碼的輸出引起的本次探索。github

let arr = [1, 2, 3]

print(arr.map{"NO.\($0)"})
print(arr.flatMap{"NO.\($0)"})
複製代碼

數組支持的map和flatMap實現

map

先貼源碼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

  1. 建立一個新的數組
  2. 遍歷數組處理閉包函數,並將結果添加到數組中
  3. 返回該數組

flatMap

結合咱們從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方法。 閉包

Optional支持的map和flatMap實現

我是看的唐巧大神的文章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

  1. flatMap的tranform返回的是U?,調用的結果return try transform(y)
  2. map返回的是U,調用的結果return .some(try transform(y))

因此map有可能形成多重Optional的問題,Optional嵌套可看唐巧大神的文章 https://blog.devtang.com/2016/02/27/swift-gym-1-nested-optional/

相關文章
相關標籤/搜索