Unions
A.k.a. Discriminated Unions (DU)
Points clés
Terme exacte : « Union discriminée », Discriminated Union (DU)
Types Somme : représente un OU, un choix entre plusieurs Cases
Même principe que pour une
enummais généralisé
Chaque case doit avoir un Tag (a.k.a Label)
C'est le discriminant de l'union pour identifier le case
Chaque case peut contenir des données
type Billet =
| Adulte // aucune donnée -> ≃ singleton stateless
| Senior of int // contient un 'int' (mais on ne sait pas ce que c'est)
| Enfant of age: int // contient un 'int' de nom 'age'
| Famille of Billet list // contient une liste de billet
// type récursif -- pas besoin de 'rec'Qualification des Tags
Les Tags peuvent être utilisés :
sans qualification →
Adultesauf pour résoudre un conflit de noms ou par choix de nommage →
Billet.Adulte
☝ On peut forcer l'usage avec qualification en décorant l'union de l'attribut RequireQualifiedAccess, essentiellement pour des raisons de nommage de l'union et de ses tags, pour que le code se lise sans ambiguïté.
Casse des Tags
Les Tags doivent être nommés en PascalCase ❗
💡 Depuis F# 7.0, la camelCase est possible si l'union est décorée avec RequireQualifiedAccess.
Champs nommés - Labelled Fields
Pratiques pour :
Ajouter un sens à un type primitif : → Dans l'exemple précédent, en ligne 4, le case
Enfantcontient un champ de typeintqui est nomméage.Distinguer deux champs du même type au sein d'un Tuple : → Exemple :
☝ Notes :
Le nommage des champs est optionnel.
En tant que champ, on optera pour le PascalCase. Mais on peut aussi les voir en tant que paramètres, alors en camelCase.
Quand un case contient plusieurs champs, on peut n'en nommer que certains. → Mais je ne recommande pas cette dissymétrie.
Déclaration
Sur plusieurs lignes : 1 ligne / case → ☝ Ligne indentée et commençant par |
Sur une seule ligne -- si déclaration reste courte ❗ → 💡 Pas besoin du 1er |
Instanciation
Tag ≃ constructeur → Fonction appelée avec les éventuelles données du case
Conflit de noms
Quand 2 unions ont des tags de même nom → Qualifier le tag avec le nom de l'union
Accès aux données internes
Uniquement via pattern matching Matching d'un type Union est exhaustif
Single-case union
Union avec un seul cas encapsulant un type (généralement primitif)
Assure type safety contrairement au simple type alias → Impossible de passer un CustomerId à une fonction attendant un OrderId 👍
Permet d'éviter Primitive Obsession à coût minime
Style "enum"
Tous les cases sont vides = dépourvus de données → ≠ enum .NET 📍Enums
L'instanciation et le pattern matching se font juste avec le tag → Le tag n'est plus une fonction mais une valeur (singleton)
Last updated
Was this helpful?