Le pattern matching est une fonctionnalité fondamentale de Swift qui rend le code plus sûr et plus propre. Historiquement, le pattern matching a été développé comme un moyen d'interagir de manière plus expressive et sécurisée avec les enum, en particulier avec des valeurs associées. Contrairement à d'autres langages, Swift permet de déballer des valeurs imbriquées directement dans les expressions if, guard, switch.
Problème : pour les enum non standards, notamment avec des valeurs associées imbriquées, il est facile de se tromper dans la structure des cases ou de sous-estimer les limitations du switch principal. De plus, la différence entre l'utilisation de if case, guard case et le switch classique n'est pas toujours évidente.
Solution : appliquer différentes approches au pattern matching selon le scénario, et pour les structures imbriquées complexes, indiquer clairement les noms et utiliser where.
Exemple de code :
enum NetworkState { case success(User) case failure(Error, code: Int) case loading(progress: Double) } let state = NetworkState.failure(SomeError(), code: 401) if case let .failure(error, code) = state, code == 401 { print("Unauthorized: \(error)") } guard case .success(let user) = state else { return } print(user) switch state { case .success(let user): print("Welcome, \(user.name)") case .failure(let error, let code) where code == 404: print("Not Found: \(error)") case .failure(_, let code): print("Failure with code: \(code)") case .loading(let progress): print("Progress: \(progress)") }
Caractéristiques clés :
Que se passe-t-il si tous les cases de l'enum ne sont pas indiqués dans le switch ?
Erreur de compilation (si enum non-optionnel) ou avertissement/exigence du case par défaut, si toutes les couvertures ne sont pas prises en compte. Pour les Optionals, il suffit d'indiquer seulement .some et .none.
Peut-on faire du pattern matching avec des enum imbriqués et des valeurs associées ?
Oui. Mais la syntaxe se complique. Pour les valeurs imbriquées, il est possible de déballer plusieurs niveaux d'un coup :
enum Outer { case inner(Inner) } enum Inner { case item(id: Int) } let e = Outer.inner(.item(id: 5)) if case let .inner(.item(id)) = e { print(id) }
En quoi guard case diffère-t-il de if case lors du pattern matching ?
guard case vérifie la condition et exécute un bloc de sortie (return, throw, break) en cas d'échec. Il est généralement utilisé pour des exigences : si ça ne correspond pas, sortir.
if case — construction adaptée pour des gestionnaires conditionnels en une ligne sans sortie de la fonction.
Un développeur utilise switch pour une enum avec plusieurs cases mais ne couvre pas un nouveau case. Le code se compile, mais le nouveau scénario n'est pas traité et l'application plante à l'exécution.
Avantages :
Inconvénients :
Un développeur couvre explicitement tous les cases, utilise where pour les filtres locaux, déballant les valeurs imbriquées par le biais de let imbriqué.
Avantages :
Inconvénients :