web-dev-qa-db-fra.com

Quand utiliser forEach (_ :) au lieu de for in?

Comme indiqué dans Array et DictionaryforEach(_:) Méthodes d'instance:

Appelle la fermeture donnée sur chaque élément de la séquence dans le même ordre qu'une boucle for-in.

Néanmoins, adapté de Aperçu de la séquence :

Une séquence est une liste de valeurs que vous pouvez parcourir pas à pas. La manière la plus courante pour parcourir les éléments d'une séquence est d'utiliser une boucle for-in .

Impliquant cette séquence d'itération par forEach(_:) ou for in:

let closedRange = 1...3

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

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

Ou (tableau):

let array = [1, 2, 3]

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

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

Donnerait la même sortie.

Pourquoi forEach(_:) existe même? c'est-à-dire quel est l'avantage de l'utiliser au lieu de la boucle for in? seraient-ils les mêmes du point de vue des performances?

Comme hypothèse, il pourrait s'agir d'un sucre syntaxique, en particulier lorsque vous travaillez avec programmation fonctionnelle.

24
Ahmad F

forEach ne présente aucun avantage en termes de performances. En fait, si vous regardez le code source , la fonction forEach effectue simplement simplement for-in. Pour les versions, la surcharge de performances de cette fonction par rapport à la simple utilisation de for-in vous-même est sans importance, bien que pour les versions de débogage, elle entraîne un impact de performance observable.

Le principal avantage de forEach est réalisé lorsque vous effectuez une programmation fonctionnelle, vous pouvez l'ajouter à une chaîne d'appels fonctionnels, sans avoir à enregistrer le résultat précédent dans une variable distincte dont vous auriez besoin si vous utilisiez for-in syntaxe. Donc, au lieu de:

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

for object in objects {
    ...
}

Vous pouvez plutôt rester dans les modèles de programmation fonctionnels:

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

Le résultat est un code fonctionnel plus concis avec moins de bruit syntaxique.

FWIW, la documentation pour Array , Dictionary , et Sequence nous rappelle tous les limitations introduites par forEach, à savoir:

  1. Vous ne pouvez pas utiliser une instruction break ou continue pour quitter l'appel en cours de la fermeture body ou ignorer les appels suivants.

  2. L'utilisation de l'instruction return dans la fermeture body ne sortira que de l'appel en cours vers body, pas de toute portée externe, et n'ignorera pas les appels suivants.

53
Rob

J'ai récemment rencontré un cas d'utilisation où l'utilisation de forEach était préférable de manière tangible à for in. Supposons que vous souhaitiez supprimer toutes les sous-couches d'un calque. Une instruction telle que la suivante ne fonctionne pas car vous devez déballer le [CALayer]

for layer in self.videoContainerView.layer.sublayers!

Si les sous-couches sont nulles, vous obtiendrez un plantage. Cela vous oblige à vérifier s'il y a d'abord des sous-couches. Cependant, un forEach rend cela beaucoup plus simple comme ci-dessous:

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

Ils sont plus ou moins interchangeables, mais il existe deux différences importantes.

  1. break/continue ne fonctionne que dans un for .. in
  2. return in forEach quittera la fermeture, mais n'arrêtera pas l'itération.

La raison en est que for .. in est un forme spéciale dans la langue (ce qui permet de faire une pause et de continuer à fonctionner comme prévu). C'est quelque chose que vous ne pouvez pas implémenter de manière identique en utilisant le langage lui-même.

Cependant, forEach n'est pas un formulaire spécial et peut être réimplémenté de manière identique en l'écrivant en tant que fonction.

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