ProgrammationDéveloppeur iOS

Comment le pattern matching fonctionne-t-il avec les structures et les enum avec des valeurs associées en Swift ? Quelle est la différence entre le matching avec `if case`, `guard case`, et `switch`, et quel est le rôle du nom du case et de la profondeur lors de l'utilisation de enum complexes ?

Réussissez les entretiens avec l'assistant IA Hintsage

Réponse.

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 :

  • Le pattern matching est possible dans switch, if case, guard case, ainsi que par le biais de let/var binding.
  • Il est possible d'effectuer des filtrages via where.
  • Dans switch, le pattern matching permet de décrire explicitement tous les cases de l'enum, garantissant l'absence de scénarios manqués.

Questions pièges.

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.

Erreurs typiques et anti-patterns

  • Omettre la couverture de tous les cases de l'enum dans switch — cela mène à des erreurs et des plantages.
  • Erreurs lors du déballage de valeurs imbriquées : noms ou niveaux d'imbrication mélangés.
  • Utilisation de if/switch pour des valeurs optionnelles sans tenir compte du case .none, ce qui conduit à une omission de scénario.

Exemple de la vie réelle

Cas négatif

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 :

  • Facile d'ajouter un gestionnaire minimal via default

Inconvénients :

  • Scénarios manqués, difficile de retracer la cause
  • Crash potentiel lors de l'apparition de nouveaux cases

Cas positif

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 :

  • Sécurité de type complète
  • Tous les scénarios sont explicitement décrits

Inconvénients :

  • Parfois excessif, switch verbeux ou double pattern matching