2017-07-26 78 views
10

作爲記錄在兩個ArrayDictionaryforEach(_:)實例方法:何時使用forEach(_ :)而不是in?

呼叫以相同的順序 在序列每個元素在給定的封閉件的for-in循環。

然而,改編自Sequence Overview

序列是,你可以在 時間通過一個步驟值的列表。 用於遍歷序列 的元素的最常用方式是使用for-in循環

言下之意是由forEach(_:)for in迭代序列:

let closedRange = 1...3 

for element in closedRange { print(element) } // 1 2 3 

closedRange.forEach { print($0) } // 1 2 3 

或(陣列):

let array = [1, 2, 3] 

for element in array { print(element) } // 1 2 3 

array.forEach { print($0) } // 1 2 3 

將給出相同的輸出。

爲什麼forEach(_:)竟然存在?即使用它代替for in循環有什麼好處?從性能角度看他們會是一樣的嗎?

作爲一個假設,它可能是一個語法糖,特別是在使用函數式編程時。

+0

從性能的角度來看'forEach'是**米ù] C H **比爲'loop'慢。但是它也可以方便地用作Objective-C的'makeObjectsPerformSelector:' – vadian

+2

@vadian - 在調試版本中它慢得多。在發佈版本中不一定是真的(顯然,取決於代碼中的其他內容)。例如,我只是通過在發佈版本中有數百萬對象的數組進行迭代測試,並且性能差異是難以區分的。 – Rob

+0

@Rob感謝您的反饋。事實上,我的「基準測試」是在調試模式下執行的(只是⌘運行該項目) – vadian

回答

15

forEach沒有性能優勢。實際上,if you look at the source code,forEach功能實際上只是執行for-in。對於發佈版本,這個函數的性能開銷通過簡單地使用for-in本身並不重要,但對於調試版本而言,它會導致可觀察的性能影響。

forEach主要優點是實現了,當你在做函數式編程,你可以將它添加到的功能調用鏈,而無需事先結果保存到一個單獨的變量,如果你使用的是for你需要 - in語法。因此,而不是:

let objects = array.map { ... } 
    .filter { ... } 

for object in objects { 
    ... 
} 

您可以改爲留內的功能的編程模式:

array.map { ... } 
    .filter { ... } 
    .forEach { ... } 

結果是功能代碼,用更少的語法噪音更簡潔。

FWIW,爲ArrayDictionary的文檔,並Sequence都提醒我們通過forEach所引入的限制的,即:

  1. 您不能使用breakcontinue聲明退出當前 通話body關閉或跳過後續的呼叫。

  2. body封閉使用return語句只會從 當前呼叫退出到body,而不是從任何外部範圍,並不會跳過 後續調用。

+0

感謝@Rob。這是否意味着我們只能通過函數式編程才能使用'forceah'? –

+0

我不會堅持只能將它與函數式編程結合使用。這是一個很好的簡潔語法,您可以隨時隨地使用它。我只是在暗示它最大的用處是與函數式編程結合使用,相比之下,''''in'模式真的變得非常麻煩。 – Rob

+0

@Rob根據你的建議,我發佈了一個與此相關的衍生問題。 https://stackoverflow.com/questions/47743259/use-foreach-to-nil-out-values-in-an-array – Adrian

-2

他們都或多或少可以互換的,但有兩個重要的區別。

  1. break/continue只在for .. in
  2. return工作,forEach將退出關閉,但不會停止迭代。

這樣做的原因是,for .. in是在語言特殊形式(允許突破,並繼續按照您的預期工作)。這是你無法用語言本身以同樣的方式實現的東西。

但是,forEach不是一種特殊形式,可以通過將其作爲函數編寫來重新實現。

extension Sequence { 
    func myOwnForEach(_ body: (Self.Element) throws -> Void) rethrows { 
     let it = Self.makeIterator() 
     while let item = it.next() { 
      body(item) 
     } 
    } 
} 
3

我最近遇到一個使用情況下使用forEach是最好有形的方式來for in跑去。假設您想要從圖層中刪除所有子圖層。如下面的說明,如你需要解開的[CALayer]

for layer in self.videoContainerView.layer.sublayers! 

如果子層零,你會得到一個崩潰不能正常工作。這迫使你先檢查是否有子層。然而,forEach使得如下面的這個更簡單:

self.videoContainerView.layer.sublayers?.forEach { $0.removeFromSuperlayer() }