La syntaxe Patterns n’est utilisable qu’à partir de Dart version ≥ 3.0
I. Rôle principal des Patterns
Le Pattern est une catégorie syntaxique indépendante en Dart (au même rang que les instructions et les expressions) qui décrit la structure d’un ensemble de valeurs. Il dispose de deux capacités majeures utilisables simultanément : la correspondance (Match) et la décomposition (Destructure).
- Correspondance Match : Vérifier si une valeur correspond à la forme attendue
- Est-ce une constante spécifique ?
- Est-ce d’un type précis ?
- Possède-t-il une structure définie (Liste/Map/Objet/Enregistrement) ?
- Satisfait-il une condition complémentaire ?
- Décomposition Destructure : Après une correspondance réussie, extraire rapidement les champs et éléments internes de la valeur pour les lier à des variables
1. Exemple de correspondance par constante
void main() {
int number = 1;
switch (number) {
case 1:
print('one'); // Correspondance par constante : number == 1
default:
print('autre valeur');
}
}Langage du code : Dart (dart)
Résultat d’exécution
one
2. Correspondance avec sous-patterns imbriqués
Les patterns acceptent l’imbrication de sous-patterns pour valider la structure interne étape par étape
void main() {
const a = 'a';
const b = 'b';
var obj = [ 'a', 'b'];
switch (obj) {
case [a, b]:
print('$a, $b');
default:
print('Aucune correspondance');
}
}Langage du code : Dart (dart)
Résultat d’exécution
a, b
3. Exemple basique de décomposition
var numList = [1, 2, 3];
// Décomposition d’une liste grâce au pattern Liste, liaison à de nouvelles variables
var [x, y, z] = numList;
print(x + y + z); // 6 x : 1 y:2 z:3Langage du code : PHP (php)
4. Correspondance + décomposition avec pattern imbriqué
void main() {
var list = ['b', 99];
switch (list) {
// Pattern OU logique : premier élément égal à a ou b, second lié à la variable c
case ['a' || 'b', var c]:
print(c); // 99
}
}Langage du code : Dart (dart)
II. Exemples courants d’utilisation des Patterns
1. Déclaration de variables locales
Utilisé pour l’affectation par décomposition, permet de créer plusieurs variables en une seule fois
// Décomposition avec pattern imbriqué Enregistrement + Liste
var (str, [n1, n2]) = ('text', [10, 20]);
print(str); //text
print(n1 + n2); //30Langage du code : Dart (dart)
2. Réaffectation de variables existantes (échange sans variable temporaire)
var (a, b) = ("gauche", "droite");
(b, a) = (a, b); // Échanger les valeurs de deux variables
print('$a $b'); // droite gaucheLangage du code : Dart (dart)
3. Branchements switch /if-case (usage fréquent, clause de garde when)
Tous les case acceptent des patterns réfutables : si la correspondance échoue, on passe au case suivant
Case basique multi-types
void testSwitch(dynamic obj) {
switch (obj) {
case 1:
print('nombre 1');
case >= 10 && <= 20:
print('nombre entre 10 et 20');
case (var a, var b):
print('enregistrement : $a,$b');
default:
print('Aucune correspondance');
}
}Langage du code : Dart (dart)
Pattern OU logique : partager une logique sur plusieurs branches
enum Color { red, yellow, blue, green }
void main() {
Color color = Color.red;
bool isPrimary = switch (color) {
Color.red || Color.yellow || Color.blue => true,
_ => false,
};
print(isPrimary); // true
}
Langage du code : PHP (php)
Clause de garde when (filtre conditionnel complémentaire après correspondance)
sealed class Shape {}
class Square { final double size; Square(this.size); }
class Circle { final double size; Circle(this.size); }
void checkShape(Shape shape) {
switch (shape) {
// Correspondre à Square et Circle simultanément, ajouter une condition size>0
case Square(size: var s) || Circle(size: var s) when s > 0:
print('Figure symétrique valide');
default:
print('Figure invalide');
}
}Langage du code : Dart (dart)
Différence entre when et un if classique
void compareWhen((int, int) pair) {
switch (pair) {
case (int a, int b):
if (a > b) print('Première valeur plus grande');
// Si l’if échoue : sortie complète du switch, les case suivants ne sont pas exécutés
case (int a, int b) when a > b:
print('【Garde when】Première valeur plus grande');
// Si when échoue : sauter uniquement ce case et tester le suivant
case (int a, int b):
print('Première valeur inférieure ou égale');
}
}
void main() {
print("===== Test (5, 2) a > b =====");
compareWhen((5, 2));
print("\n===== Test (2, 5) a < b =====");
compareWhen((2, 5));
}Langage du code : Dart (dart)
4. Boucles for /for-in (décomposition MapEntry très pratique)
void main() {
Map<String, int> hist = {'a': 23, 'b': 100};
// Écriture complète
for (var MapEntry(key: key, value: count) in hist.entries) {
print('$key : $count');
}
// Syntaxe abrégée : key:key simplifié en :key
for (var MapEntry(:key, value: count) in hist.entries) {
print('$key : $count');
}
}Langage du code : Dart (dart)
Résultat d’exécution
D:\dartdemo\firstdart>dart run
Building package executable...
Built firstdart:firstdart.
a : 23
b : 100
a : 23
b : 100
Langage du code : CSS (css)
III. Cas d’usage métier des Patterns
1 : Valeurs de retour multiples d’une fonction (décomposition d’enregistrements)
Méthode traditionnelle (lourde)
(String, int) userInfo() => ("Lily", 13);
void main() {
var info = userInfo();
var name = info.$1;
var age = info.$2;
}
Langage du code : Dart (dart)
Écriture simplifiée par pattern
var (name, age) = userInfo();
// Décomposition d’enregistrement à champs nommés
final (:name, :age) = getData(); // Retour (name: "Doug", age:25)Langage du code : Dart (dart)
Exemple concret
(String, int) userInfo() => ("Lily", 18);
({String name, int age}) getData() => (name: "Doug", age: 25);
void main() {
{
var (name, age) = userInfo();
print("Prénom : $name, âge : $age");
}
// Les variables name/age internes n’interfèrent pas avec celles du dessus
{
final (:name, :age) = getData();
print("Prénom : $name, âge : $age");
}
}Langage du code : Dart (dart)
2 : Décomposition d’instances de classe (pattern objet)
class Foo {
final String one;
final int two;
Foo({required this.one, required this.two});
}
void main() {
final Foo myFoo = Foo(one: "test", two: 66);
var Foo(:one, :two) = myFoo;
print('$one $two'); //test 66
}Langage du code : Dart (dart)
3 : Types de données algébriques (classes sealed + calcul par branche switch)
Gérer uniformément un groupe de sous-classes liées sans éparpiller des méthodes d’instance
import 'dart:math';
sealed class Shape {}
class Square implements Shape { final double length; Square(this.length); }
class Circle implements Shape { final double radius; Circle(this.radius); }
double calculateArea(Shape shape) => switch (shape) {
Square(length: var l) => l * l,
Circle(radius: var r) => pi * r * r,
};
Langage du code : Dart (dart)
Exemple complet
import 'dart:math';
// Classe parent scellée, sous-classes uniquement dans ce fichier
sealed class Shape {}
// Sous-classe Carré
class Square implements Shape {
final double length;
Square(this.length);
}
// Sous-classe Cercle
class Circle implements Shape {
final double radius;
Circle(this.radius);
}
// Calcul uniforme de l’aire avec expression switch + pattern objet
double calculateArea(Shape shape) => switch (shape) {
// Correspondre à Square, extraire length dans la variable l
Square(length: var l) => l * l,
// Correspondre à Circle, extraire radius dans la variable r
Circle(radius: var r) => pi * r * r,
};
void main() {
// Créer des instances de figures
Shape square = Square(5);
Shape circle = Circle(3);
// Calcul des aires
double squareArea = calculateArea(square);
double circleArea = calculateArea(circle);
print("Aire du carré : $squareArea"); // 25.0
print("Aire du cercle : ${circleArea.toStringAsFixed(2)}"); // 28.27
}Langage du code : Dart (dart)
Résultat d’exécution
D:\dartdemo\firstdart>dart run
Building package executable...
Built firstdart:firstdart.
Aire du carré : 25.0
Aire du cercle : 28.27Langage du code : CSS (css)
4 : Vérification et décomposition de données JSON (simplifie grandement les imbrications de conditions)
(Sans patterns) Multiples vérifications de type imbriquées, code verbeux
void oldCheck(Map data) {
if (data is Map<String, Object?> && data.containsKey('user')) {
var user = data['user'];
if (user is List && user.length == 2) {
String name = user[0] as String;
int age = user[1] as int;
print('$name $age');
}
}
}Langage du code : Dart (dart)
Pattern if-case : une seule ligne pour validation structure + validation type + liaison variable
void newCheck(Map data) {
if (data case {'user': [String name, int age]}) {
print('Utilisateur $name, âge $age');
}
}Langage du code : Dart (dart)
Ce pattern valide simultanément ces points :
- data est un Map et non nul
- la clé user existe
- la valeur associée à user est une liste de 2 éléments
- premier élément String, second int
- liaison automatique des variables locales name et age
Exemple d’utilisation concret
void main() {
// 1. Structure JSON valide : correspondance réussie
final validJson = {
'user': ['Lily', 13]
};
newCheck(validJson); // Affichage : Utilisateur Lily, âge 13
// 2. Incompatibilité de type dans la liste : âge en chaîne, échec correspondance
final wrongTypeJson = {
'user': ['Tom', '16']
};
newCheck(wrongTypeJson); // Aucun affichage
// 3. Liste user incomplète : échec (pas de donnée d’âge)
final shortJson = {
'user': ['Jack']
};
newCheck(shortJson); // Aucun affichage
// 4. Absence de la clé user : échec
final noUserJson = {
'info': ['Bob', 20]
};
newCheck(noUserJson); // Aucun affichage
}
// Vérification structure/type et décomposition en une étape avec pattern Map+List if-case
void newCheck(Map data) {
if (data case {'user': [String name, int age]}) {
print('Utilisateur $name, âge $age');
} else {
print('Format de données invalide');
}
}Langage du code : PHP (php)
Mise en correspondance par Pattern