Le langage de programmation 
Swift n'a que quatre ans, mais il devient déjà le principal langage de développement pour iOS. En développant la version 5.0, Swift est devenu un langage complexe et puissant qui répond à la fois à un paradigme orienté objet et fonctionnel. Et à chaque nouvelle version, il ajoute encore plus de fonctionnalités.
Mais comment connaissez-vous 
vraiment Swift? Dans cet article, vous trouverez des exemples de questions pour une interview Swift.
Vous pouvez utiliser ces questions pour interroger les candidats afin de tester leurs connaissances ou vous pouvez tester les vôtres. Si vous ne connaissez pas la réponse, ne vous inquiétez pas: il y a une réponse à chaque question.
Les questions sont divisées en trois groupes:
- Débutant : pour les débutants. Vous avez lu quelques livres et appliqué Swift dans vos propres applications.
- Intermédiaire : adapté à ceux qui sont vraiment intéressés par la langue. Vous en avez déjà beaucoup lu et expérimentez souvent.
- Avancé : adapté aux développeurs les plus avancés - ceux qui aiment entrer dans la jungle de la syntaxe et utiliser des techniques avancées.
Il existe deux types de questions pour chaque niveau:
- écrit : adapté aux tests par e-mail, car ils suggèrent d'écrire du code.
- oral : peut être utilisé lorsque vous parlez au téléphone ou en personne, car il y a suffisamment de réponses en mots.
Pendant que vous lisez cet article, gardez le 
terrain de jeu ouvert pour pouvoir vérifier le code de la question. Toutes les réponses ont été testées sur 
Xcode 10.2 et 
Swift 5 .
- Débutant
 - questions écrites- Question 1- Considérez le code suivant: - struct Tutorial { var difficulty: Int = 1 } var tutorial1 = Tutorial() var tutorial2 = tutorial1 tutorial2.difficulty = 2
 - Quelles sont les valeurs de  tutorial1.difficulty-  et  tutorial2.difficulty-  ? Y aurait-il une différence si le  didacticiel-  était une classe? Pourquoi? - la réponse- tutorial1.difficulty vaut 1 et tutorial2.difficulty vaut 2. - Dans Swift, les structures sont des types de valeur. Ils sont copiés, non référencés. La ligne suivante copie  tutorial1-  et l'affecte à  tutorial2-  : -  - var tutorial2 = tutorial1
 - Les modifications apportées à  tutorial2-  n'affectent pas  tutorial1-  . - Si Tutorial était une classe,  tutorial1.difficulty-  et  tutorial2.difficulty-  seraient égaux à 2. Les classes dans Swift sont des types de référence. Lorsque vous modifiez la propriété tutorial1, vous verrez la même modification pour tutorial2 - et vice versa. 
 
 - Question 2- Vous avez déclaré  view1-  avec  var-  et  view2-  avec  let-  . Quelle est la différence et la dernière ligne est-elle compilée? -  - import UIKit var view1 = UIView() view1.alpha = 0.5 let view2 = UIView() view2.alpha = 0.5 
 - la réponse- Oui, la dernière ligne est compilée.  view1-  est une variable et vous pouvez affecter sa valeur à une nouvelle instance de UIView. En utilisant  let-  , vous ne pouvez affecter une valeur qu'une seule fois, de sorte que le code suivant ne se compile pas: -  - view2 = view1 
 - Cependant, UIView est une classe avec une sémantique référentielle, vous pouvez donc modifier les propriétés de view2 - ce qui signifie que le code sera  compilé-  . 
 
 - Question 3- Ce code trie le tableau par ordre alphabétique. Simplifiez autant que possible la fermeture. -  - var animals = ["fish", "cat", "chicken", "dog"] animals.sort { (one: String, two: String) -> Bool in return one < two } print(animals)
 - la réponse- Swift  détermine automatiquement le-  type de paramètres de fermeture et le type de retour, vous pouvez donc les  supprimer-  : -  - animals.sort { (one, two) in return one < two }
 - Vous pouvez remplacer les noms de paramètres à l'aide de la notation  $ i-  : -  - animals.sort { return $0 < $1 }
 - Les fermetures consistant en une seule instruction peuvent ne pas contenir le mot-clé  return-  . La valeur de la dernière instruction exécutée devient le résultat de retour de la fermeture: -  - animals.sort { $0 < $1 }
 - Enfin, puisque Swift sait que les éléments du tableau sont conformes au protocole  Equatable-  , vous pouvez simplement écrire: -  - animals.sort(by: <)
 - Upd:  hummingbirddj-  simplifié encore plus: - Dans ce cas, vous pouvez même raccourcir:-  -  animals.sort()
 - Trie par ordre croissant, fonctionne pour les types qui implémentent Comparable.
 
 
 - Question 4- Ce code crée deux classes:  Adresse-  et  Personne-  . Deux instances de la classe  Person-  (  Ray-  et  Brian-  ) sont également créées. -  - class Address { var fullAddress: String var city: String init(fullAddress: String, city: String) { self.fullAddress = fullAddress self.city = city } } class Person { var name: String var address: Address init(name: String, address: Address) { self.name = name self.address = address } } var headquarters = Address(fullAddress: "123 Tutorial Street", city: "Appletown") var ray = Person(name: "Ray", address: headquarters) var brian = Person(name: "Brian", address: headquarters)
 - Supposons que  Brian a-  déménagé vers une nouvelle adresse et que vous souhaitez mettre à jour son enregistrement comme suit: -  - brian.address.fullAddress = "148 Tutorial Street"
 - Cela se compile et s'exécute sans erreur. Mais, si vous vérifiez maintenant l'adresse de  Ray-  , vous verrez qu'il a également  «déménagé»-  . - Que s'est-il passé ici et comment pouvons-nous y remédier? - la réponse- L'adresse est une classe et possède une sémantique de référence . Ainsi, le quartier général est la même instance de la classe partagée par ray et brian. Changer le siège changera l'adresse des deux.
 Pour résoudre ce problème, vous pouvez créer une nouvelle instance de la classe Address et l'affecter à Brian, ou déclarer Address en tant que structure au lieu d'une classe .
 
 
 
 
 
 - questions orales- Question 1- Qu'est-ce qui est  facultatif-  et quels problèmes résolvent-ils? - la réponse- facultatif permet à une variable de tout type de présenter une situation " sans valeur ". Dans Objective-C, "aucune valeur" n'était disponible que dans les types de référence utilisant la valeur spéciale nil . Les types de valeur, tels que int ou float , n'avaient pas cette capacité.
 Swift a étendu le concept de «aucune valeur» aux types de valeur. La variable facultative peut contenir une valeur ou nil , indiquant l'absence d'une valeur.
 
 
 
 - Question 2- Énumérez brièvement les principales différences entre la  structure-  et la  classe-  . - la réponse- Les classes prennent en charge l'héritage, mais pas les structures.
 Les classes sont un type de référence, les structures sont un type de valeur.
 
 
 
 - Question 3- Que sont les  génériques-  et à quoi servent-ils? - la réponse- Dans Swift, vous pouvez utiliser des  génériques-  dans les classes, les structures et les énumérations. Les génériques-  résolvent le problème de duplication de code. Si vous avez une méthode qui accepte les paramètres d'un type, vous devez parfois dupliquer du code pour travailler avec des paramètres d'un autre type. - Par exemple, dans ce code, la deuxième fonction est un «clone» de la première, sauf qu'elle a des paramètres de chaîne et non un entier. -  - func areIntEqual(_ x: Int, _ y: Int) -> Bool { return x == y } func areStringsEqual(_ x: String, _ y: String) -> Bool { return x == y } areStringsEqual("ray", "ray") 
 - En utilisant des génériques, vous combinez deux fonctions en une et garantissez en même temps la sécurité du type: -  - func areTheyEqual<T: Equatable>(_ x: T, _ y: T) -> Bool { return x == y } areTheyEqual("ray", "ray") areTheyEqual(1, 1)
 - Puisque vous testez l'égalité, vous limitez les types à ceux qui sont conformes au protocole  Equatable-  . Ce code fournit le résultat souhaité et empêche le transfert de paramètres de type incorrect. 
 
 - Question 4- Dans certains cas, il ne sera pas possible d'éviter les options implicitement  déballées-  . Quand et pourquoi? - la réponse- Les raisons les plus courantes d'utiliser des options implicitement non enveloppées sont: - lorsque vous ne pouvez pas initialiser une propriété qui n'est pas nulle au moment de la création. Un exemple typique est le point de vente d'Interface Builder, qui est toujours initialisé après son propriétaire. Dans ce cas particulier, si tout est correctement configuré dans Interface Builder, vous avez la garantie que la prise n'est pas nulle avant de l'utiliser.
- pour résoudre le problème de la boucle des références fortes , lorsque deux instances de classes se réfèrent l'une à l'autre et qu'une référence non nulle à une autre instance est requise. Dans ce cas, vous marquez le lien d'un côté comme non propriétaire , et de l'autre côté utilisez une extension optionnelle implicite.
 
 
 - Question 5- Quelles sont les méthodes de déploiement facultatives? Évaluez-les en termes de sécurité. -  - var x : String? = "Test"
 - Astuce: seulement 7 façons. - la réponse- Le déballage forcé-  n'est pas sûr. -  - let a: String = x!
 Le déploiement implicite lors de la déclaration d'une variable-  n'est pas sûr. -  - var a = x!
 La reliure optionnelle-  est sûre. -  - if let a = x { print("x was successfully unwrapped and is = \(a)") }
 Le chaînage optionnel-  est sûr. -  - let a = x?.count
 L'opérateur de coalescence nul-  est sûr. -  - let a = x ?? ""
 - La déclaration de la  Garde-  est sûre. -  - guard let a = x else { return }
 Modèle optionnel-  - sûr. -  - if case let a? = x { print(a) }
 
 
 
 
 
 
- Intermédiaire
 - questions écrites- Question 1- Quelle est la difference entre  nil-  et  .none-  ? - la réponse- Il n'y a aucune différence,  Optional.none-  (brièvement  .none-  ) et  nil sont-  équivalents. - En fait, l'instruction suivante retournera  vrai-  : -  - nil == .none
 - L'utilisation de  néant est-  plus généralement acceptée et recommandée. 
 
 - Question 2- Voici un modèle de thermomètre sous forme de classe et de structure. Le compilateur se plaint de la dernière ligne. Qu'est-ce qui ne va pas? -  - public class ThermometerClass { private(set) var temperature: Double = 0.0 public func registerTemperature(_ temperature: Double) { self.temperature = temperature } } let thermometerClass = ThermometerClass() thermometerClass.registerTemperature(56.0) public struct ThermometerStruct { private(set) var temperature: Double = 0.0 public mutating func registerTemperature(_ temperature: Double) { self.temperature = temperature } } let thermometerStruct = ThermometerStruct() thermometerStruct.registerTemperature(56.0)
 - la réponse- ThermometerStruct est correctement déclaré avec une fonction de mutation pour changer la variable interne. Le compilateur se plaint que vous appelez la méthode registerTemperature de l'instance qui a été créée avec let , donc cette instance est immuable. Changer let en var corrigera l'erreur de compilation.
 
 Dans les structures, vous devez marquer les méthodes qui modifient les variables internes comme mutantes , mais vous ne pouvez pas appeler ces méthodes à l'aide d'une instance immuable.
 
 
 
 - Question 3- Que produira ce code et pourquoi? -  - var thing = "cars" let closure = { [thing] in print("I love \(thing)") } thing = "airplanes" closure()
 - la réponse- Il sera imprimé: j'adore les voitures. La liste de capture crée une copie de la variable lorsque la fermeture est déclarée. Cela signifie que la variable capturée ne changera pas sa valeur, même après l'attribution d'une nouvelle valeur. - Si vous omettez la liste de capture dans la fermeture, le compilateur utilisera le lien, pas la copie. L'appel de clôture reflétera le changement de la variable: -  - var thing = "cars" let closure = { print("I love \(thing)") } thing = "airplanes" closure() 
 
 
 - Question 4- Il s'agit d'une fonction qui compte le nombre de valeurs uniques dans un tableau: -  - func countUniques<T: Comparable>(_ array: Array<T>) -> Int { let sorted = array.sorted() let initial: (T?, Int) = (.none, 0) let reduced = sorted.reduce(initial) { ($1, $0.0 == $1 ? $0.1 : $0.1 + 1) } return reduced.1 }
 - Il utilise trié, il n'utilise donc que des types conformes au protocole comparable. - Vous pouvez l'appeler comme ceci: -  - countUniques([1, 2, 3, 3]) 
 - Réécrivez cette fonction en tant qu'extension de tableau afin de pouvoir l'utiliser comme ceci: -  - [1, 2, 3, 3].countUniques() 
 - note du traducteur- Quelque chose de trop douloureux est une fonction monstrueuse. Pourquoi pas: -  - func countUniques<T: Hashable>(_ array: Array<T>) -> Int { return Set(array).count }
 
 - la réponse-  - extension Array where Element: Comparable { func countUniques() -> Int { let sortedValues = sorted() let initial: (Element?, Int) = (.none, 0) let reduced = sortedValues.reduce(initial) { ($1, $0.0 == $1 ? $0.1 : $0.1 + 1) } return reduced.1 } }
 
 
 - Question 5- Voici une fonction qui divise deux doubles optionnels. Trois conditions doivent ĂŞtre remplies: - le dividende ne doit pas ĂŞtre nul
- le diviseur ne doit pas ĂŞtre nul
- le diviseur ne doit pas ĂŞtre 0
 -  - func divide(_ dividend: Double?, by divisor: Double?) -> Double? { if dividend == nil { return nil } if divisor == nil { return nil } if divisor == 0 { return nil } return dividend! / divisor! }
 - Réécrivez cette fonction à l'aide de l'instruction  guard-  et non à l'aide du déballage forcé. - la réponse- L'instruction  guard-  introduite dans Swift 2.0 fournit une sortie si la condition n'est pas remplie. Voici un exemple: -  - guard dividend != nil else { return nil }
 - Vous pouvez également utiliser l'instruction guard pour la  liaison facultative-  , après quoi la variable développée sera disponible en  dehors de l'instruction guard-  : -  - guard let dividend = dividend else { return .none }
 - Vous pouvez donc réécrire la fonction comme ceci: -  - func divide(_ dividend: Double?, by divisor: Double?) -> Double? { guard let dividend = dividend else { return nil } guard let divisor = divisor else { return nil } guard divisor != 0 else { return nil } return dividend / divisor }
 - Faites attention à l'absence de décompression forcée, car nous avons déjà décompressé le dividende et le diviseur et les avons placés dans des variables immuables non facultatives. - Notez également que le résultat des options non emballées dans la déclaration de garde est également disponible en dehors de la déclaration de garde. - Vous pouvez simplifier davantage la fonction en regroupant les instructions de garde: -  - func divide(_ dividend: Double?, by divisor: Double?) -> Double? { guard let dividend = dividend, let divisor = divisor, divisor != 0 else { return nil } return dividend / divisor }
 
 
 - Question 6- Réécrivez la méthode de la question 5 à l'aide de l'  instruction if let-  . - la réponse- L'instruction if let vous permet de décompresser les options et d'utiliser cette valeur dans ce bloc de code. En dehors de cela, ces valeurs ne seront pas disponibles. -  - func divide(_ dividend: Double?, by divisor: Double?) -> Double? { if let dividend = dividend, let divisor = divisor, divisor != 0 { return dividend / divisor } else { return nil } }
 
 
 
 
 - questions orales- Question 1- Dans Objective-C, vous déclarez une constante comme celle-ci: -  - const int number = 0;
 - Et donc dans Swift: -  - let number = 0
 - Quelle est la différence? - la réponse- Dans  Objective-C, une-  constante est initialisée  au moment de la compilation avec une-  valeur qui devrait être connue à ce stade. - Une valeur immuable créée avec  let-  est une constante définie  au moment de l'exécution-  . Vous pouvez l'initialiser avec une expression statique ou dynamique. Par conséquent, nous pouvons le faire: -  - let higherNumber = number + 5
 - Veuillez noter qu'une telle mission ne peut être effectuée qu'une seule fois. 
 
 - Question 2- Pour déclarer une propriété ou une fonction statique pour les types de valeur, le modificateur  statique-  est utilisé. Voici un exemple pour la structure: -  - struct Sun { static func illuminate() {} }
 - Et pour les classes, il est possible d'utiliser  des-  modificateurs  statiques-  ou de  classe-  . Le résultat est le même, mais il y a une différence. Décrivez-le. - la réponse- statique-  rend une propriété ou une fonction statique et  sans chevauchement-  . L'utilisation de la classe  remplacera une-  propriété ou une fonction. - Ici, le compilateur jurera lors d'une tentative de remplacement de  illuminate ()-  : -  - class Star { class func spin() {} static func illuminate() {} } class Sun : Star { override class func spin() { super.spin() } 
 
 
 
 - Question 3- Est-il possible d'ajouter une  propriété stockée-  à un type à l'aide d'une  extension-  ? Comment ou pourquoi pas? - la réponse- Non, ce n'est pas possible. Nous pouvons utiliser l'extension pour ajouter un nouveau comportement à un type existant, mais nous ne pouvons pas changer le type lui-même ou son interface. Pour stocker la nouvelle propriété stockée, nous avons besoin de mémoire supplémentaire et l'extension ne peut pas le faire.
 
 
 
 - Question 4- Qu'est-ce qu'un protocole dans Swift? - la réponse- Un protocole est un type qui définit un aperçu des méthodes, des propriétés, etc. Une classe, une structure ou une énumération peut prendre un protocole pour implémenter tout cela. Le protocole lui-même n'implémente pas la fonctionnalité, mais la définit.
 
 
 
 
 
 
- Avancé
 - questions écrites- Question 1- Supposons que nous ayons une structure qui définit le modèle d'un thermomètre: -  - public struct Thermometer { public var temperature: Double public init(temperature: Double) { self.temperature = temperature } }
 - Pour créer une instance, nous écrivons: -  - var t: Thermometer = Thermometer(temperature:56.8)
 - Mais quelque chose comme ça serait beaucoup plus pratique: -  - var thermometer: Thermometer = 56.8
 - Est-ce possible? Comment? - la réponse- Swift définit des protocoles qui vous permettent d'initialiser un type à l'aide de littéraux par affectation. L'application du protocole approprié et la fourniture d'un initialiseur public permettront l'initialisation à l'aide de littéraux. Dans le cas du thermomètre, nous implémentons  ExpressibleByFloatLiteral-  : -  - extension Thermometer: ExpressibleByFloatLiteral { public init(floatLiteral value: FloatLiteralType) { self.init(temperature: value) } }
 - Maintenant, nous pouvons créer une instance comme celle-ci: -  - var thermometer: Thermometer = 56.8
 
 
 - Question 2- Swift dispose d'un ensemble d'opérateurs prédéfinis pour les opérations arithmétiques et logiques. Il vous permet également de créer vos propres opérateurs, à la fois unaires et binaires. - Définissez et implémentez votre propre opérateur d'exponentiation (^^) selon les exigences suivantes: - prend deux int comme paramètres
- renvoie le résultat de l'augmentation du premier paramètre à la puissance du second
- traite correctement l'ordre des opérations algébriques
- ignore les éventuelles erreurs de débordement
 - la réponse- La création d'un nouvel opérateur se déroule en deux étapes: l'annonce et la mise en œuvre. - La déclaration utilise le mot-clé  operator-  pour spécifier le type (unaire ou binaire), pour spécifier la séquence de caractères du nouvel opérateur, son associativité et la priorité d'exécution. - Ici, l'opérateur est ^^ et son type est infixe (binaire). L'associativité a raison. - Swift n'a pas d'ancienneté prédéfinie pour l'exponentiation. En algèbre, l'exponentiation doit être calculée avant multiplication / division. Ainsi, nous créons un ordre d'exécution personnalisé en plaçant l'exponentiation plus haut que la multiplication. - Cette annonce: -  - precedencegroup ExponentPrecedence { higherThan: MultiplicationPrecedence associativity: right } infix operator ^^: ExponentPrecedence
 - Voici l'implémentation: -  - func ^^(base: Int, exponent: Int) -> Int { let l = Double(base) let r = Double(exponent) let p = pow(l, r) return Int(p) }
 
 
 - Question 3- Le code suivant définit la structure de  Pizza-  et le protocole  Pizzeria-  avec une extension pour l'implémentation par défaut de la méthode  makeMargherita ()-  : -  - struct Pizza { let ingredients: [String] } protocol Pizzeria { func makePizza(_ ingredients: [String]) -> Pizza func makeMargherita() -> Pizza } extension Pizzeria { func makeMargherita() -> Pizza { return makePizza(["tomato", "mozzarella"]) } }
 - Nous définissons maintenant le restaurant  Lombardis-  : -  - struct Lombardis: Pizzeria { func makePizza(_ ingredients: [String]) -> Pizza { return Pizza(ingredients: ingredients) } func makeMargherita() -> Pizza { return makePizza(["tomato", "basil", "mozzarella"]) } }
 - Le code suivant crée deux instances de  Lombardis-  . Lequel d'entre eux fait de la margarita au basilic? -  - let lombardis1: Pizzeria = Lombardis() let lombardis2: Lombardis = Lombardis() lombardis1.makeMargherita() lombardis2.makeMargherita()
 - la réponse- Dans les deux. Le protocole  Pizzeria-  déclare la méthode  makeMargherita ()-  et fournit une implémentation par défaut. L'implémentation de  Lombardis-  remplace la méthode par défaut. Puisque nous avons déclaré la méthode dans le protocole à deux endroits, l'implémentation correcte sera appelée. - Mais que se passe-t-il si le protocole ne déclare pas la méthode  makeMargherita ()-  et que l'extension fournit toujours l'implémentation par défaut, comme ceci: -  - protocol Pizzeria { func makePizza(_ ingredients: [String]) -> Pizza } extension Pizzeria { func makeMargherita() -> Pizza { return makePizza(["tomato", "mozzarella"]) } }
 - Dans ce cas, seul lombardis2 aurait une pizza au basilic, tandis que lombardis1 n'aurait pas de pizza, car il utiliserait la méthode définie en extension. 
 
 - Question 4- Le code suivant ne se compile pas. Pouvez-vous expliquer ce qui ne va pas avec lui? Suggérez des solutions au problème. -  - struct Kitten { } func showKitten(kitten: Kitten?) { guard let k = kitten else { print("There is no kitten") } print(k) }
 - Astuce: Il existe trois façons de corriger l'erreur. - la réponse- Le bloc  else-  de l'instruction  guard-  nécessite une option de sortie, soit en utilisant  return-  , en lançant une exception ou en appelant  @noreturn-  . La solution la plus simple consiste à ajouter une  déclaration de retour-  . -  - func showKitten(kitten: Kitten?) { guard let k = kitten else { print("There is no kitten") return } print(k) }
 - Cette solution lèvera une exception: -  - enum KittenError: Error { case NoKitten } struct Kitten { } func showKitten(kitten: Kitten?) throws { guard let k = kitten else { print("There is no kitten") throw KittenError.NoKitten } print(k) } try showKitten(kitten: nil)
 - Enfin, voici l'appel Ă   fatalError ()-  , la fonction  @noreturn-  . -  - struct Kitten { } func showKitten(kitten: Kitten?) { guard let k = kitten else { print("There is no kitten") fatalError() } print(k) }
 
 
 
 
 - questions orales- Question 1- Les fermetures sont-elles un type de référence ou un type de valeur? - la réponse- Les fermetures sont un type de référence. Si vous affectez une fermeture à une variable, puis la copiez dans une autre variable, vous copiez le lien vers la même fermeture et sa liste de capture.
 
 
 
 - Question 2- Vous utilisez le type  UInt-  pour stocker un entier non signé. Il implémente un initialiseur pour convertir à partir d'un tout avec un signe: -  - init(_ value: Int)
 - Toutefois, le code suivant ne compile pas si vous spécifiez une valeur négative: -  - let myNegative = UInt(-1)
 - Les entiers signés, par définition, ne peuvent pas être négatifs. Cependant, il est possible d'utiliser la représentation d'un nombre négatif en mémoire pour le traduire en non signé. - Comment puis-je convertir un entier négatif en UInt tout en conservant sa représentation en mémoire? - la réponse- Il existe un initialiseur pour cela: -  - UInt(bitPattern: Int)
 - Et utilisez: -  - let myNegative = UInt(bitPattern: -1)
 
 
 - Question 3- Décrire les références circulaires dans Swift? Comment peuvent-ils être réparés? - la réponse- Les références circulaires se produisent lorsque deux instances contiennent une référence forte l'une à l'autre, ce qui conduit à une fuite de mémoire car aucune de ces instances ne peut être libérée. Une instance ne peut pas être libérée tant qu'il y a encore des références fortes, mais une instance contient l'autre.
 
 Cela peut être résolu en remplaçant le lien d'un côté en spécifiant le mot clé faible ou sans propriétaire .
 
 
 
 - Question 4- Swift vous permet de créer des énumérations récursives. Voici un exemple d'une telle énumération qui contient une variante de nœud avec deux types associatifs, T et List: -  - enum List<T> { case node(T, List<T>) }
 - Il y aura une erreur de compilation. Qu'avons-nous manqué? - la réponse- Nous avons oublié le mot-clé  indirect-  , qui permet des options d'énumération récursives similaires: -  - enum List<T> { indirect case node(T, List<T>) }