Flux de contrôle par branchements

I. Branchements basiques if / if-else

  1. L’expression entre parenthèses de if doit obligatoirement être booléenne ; la conversion implicite en booléen est interdite.
  2. On peut enchaîner plusieurs blocs else if, avec un bloc else facultatif à la fin.
  3. Les accolades peuvent être omises pour une seule ligne, mais il est recommandé de les ajouter systématiquement pour améliorer la lisibilité.
void main() {
  bool isRaining = false;
  bool isSnowing = true;

  if (isRaining) {
    print("Prendre un imperméable");
  } else if (isSnowing) {
    print("Porter une épaisse veste");
  } else {
    print("Conduire une décapotable");
  }
}Langage du code : Dart (dart)

Résultat d’exécution

D:\dartdemo\firstdart>dart run
Building package executable...
Built firstdart:firstdart.
Porter une épaisse vesteLangage du code : CSS (css)

Il est aussi possible d’utiliser if seul

void main() {
  bool isRaining = false;
  bool isSnowing = true;

  if (isRaining) {
    print("Prendre un imperméable");
  }
}Langage du code : Dart (dart)

Ou simplement un if else

void main() {
  bool isRaining = false;
  bool isSnowing = true;

  if (isRaining) {
    print("Prendre un imperméable");
  } else {
    print("Conduire une décapotable");
  }
}Langage du code : Dart (dart)

II. Branchement par motif if-case (Dart 3.0+)

  1. Le motif est vérifié ; en cas de correspondance, les variables sont déstructurées et liées à la portée actuelle.
  2. Si la correspondance échoue, on bascule vers else ; on peut ajouter un garde when pour un contrôle booléen complémentaire.
  3. Destiné à la correspondance une valeur, un seul motif ; utilisez switch pour gérer plusieurs motifs.
void main() {
  final pair = [100, 220];
  // Correspond à une liste de deux entiers
  if (pair case [int x, int y]) {
    print("Coordonnées : $x,$y");
  } else {
    throw FormatException("Coordonnées invalides");
  }
}Langage du code : Dart (dart)

Résultat d’exécution

D:\dartdemo\firstdart>dart run
Building package executable...
Built firstdart:firstdart.
Coordonnées : 10,20Langage du code : CSS (css)

2 : if-case associé au garde when

void main() {
  final data = [8, 9];
  if (data case [int a, int b] when a > 5 && b > 5) {
    print("Les deux nombres sont supérieurs à 5");
  } else {
    print("Les nombres ne satisfont pas la condition");
  }
}Langage du code : Dart (dart)

Résultat d’exécution

D:\dartdemo\firstdart>dart run
Building package executable...
Built firstdart:firstdart.
Les deux nombres sont supérieurs à 5Langage du code : CSS (css)

III. Instruction switch

Switch traditionnel sous forme d’instruction, sans valeur de retour

  1. Les cases acceptent tous types de motifs : chaînes de caractères, constantes, OU logique, motifs relationnels
  2. Les cases non vides se terminent automatiquement par break, nul besoin d’écrire break manuellement ; les cases vides provoquent une chute implicite.
  3. Deux manières de forcer la chute : continue étiquette ou enchaînement de cases vides
  4. L’instruction default s’exécute quand aucune case ne correspond ; compatible avec les gardes when
1 : Correspondance basique sur chaîne
void main() {
  String command = "OPEN";
  switch (command) {
    case "CLOSED":
      print("Exécuter la logique de fermeture");
    case "PENDING":
      print("Exécuter la logique d’attente");
    case "OPEN":
      print("Exécuter la logique d’ouverture");
    default:
      print("Commande inconnue");
  }
}
Langage du code : Dart (dart)

Résultat d’exécution

D:\dartdemo\firstdart>dart run
Building package executable...
Built firstdart:firstdart.
Exécuter la logique douvertureLangage du code : CSS (css)

2 : Chute de case vide + saut avec continue et étiquette

String command = "OPEN";
switch (command) {
  case "OPEN":
    print("Action d’ouverture"); // ① Correspond à OPEN et affiche le message
    continue newCase; // ② Saute directement vers l’étiquette newCase sans revenir en arrière

  case "DENIED": 
  case "CLOSED":
    print("Action de fermeture");

  newCase: // ③ Cible du saut
  case "PENDING":
    print("Logique unifiée des traitements en attente"); // ④ Exécuté sans vérifier command == "PENDING"
}Langage du code : Dart (dart)

Résultat d’exécution

D:\dartdemo\firstdart>dart run
Building package executable...
Built firstdart:firstdart.
Action douverture
Logique unifiée des traitements en attenteLangage du code : CSS (css)

Dans cet exemple, continue newCase; saute vers l’étiquette newCase, mais le case suivant « PENDING » ne correspond pas, pourquoi print("Logique unifiée des traitements en attente"); s’exécute tout de même ?

Beaucoup de lecteurs se posent cette question

continue étiquette; ne réévalue pas la valeur testée, il saute directement au début du bloc case marqué par l’étiquette, ignore tout contrôle de condition et exécute immédiatement le code du bloc.

3 : switch associé au garde when

void main() {
  int score = 88;
  switch (score) {
    case int s when s >= 90:
      print("Excellent");
    case int s when s >= 60:
      print("Valide");
    default:
      print("Échec");
  }
}
Langage du code : Dart (dart)

Sortie : Valide

On vérifie d’abord le type : la valeur doit être un entier. Si c’est le cas, on l’affecte à s. Ensuite le garde when réalise une seconde vérification ; le code du case ne s’exécute que si s respecte la condition du when. Ici, les deux déclarations int s ont des portées indépendantes et ne se perturbent pas.

Chaque case int s correspond à un liaison de motif indépendante, dont la portée se limite uniquement à son propre bloc case, sans interférence avec les autres.

Vous pouvez parfaitement utiliser des noms de variables différents sans changer le comportement du programme.

switch (score) {
  case int a when a >= 90:
    print("Excellent");
  case int b when b >= 60:
    print("Valide");
  default:
    print("Échec");
}Langage du code : Dart (dart)

IV. Expression switch

Syntaxe disponible à partir de Dart 3.0, renvoie une valeur et est très utilisée pour les affectations

Différences avec l’instruction switch

  1. Pas de mot-clé case ; le symbole => sépare le motif et l’expression de retour
  2. Chaque branche doit renvoyer une expression, les branches sont séparées par des virgules
  3. Aucune chute implicite, chaque branche est isolée. Quand aucun motif ne correspond, utilisez le underscore _ au lieu de default
  4. Utilisable directement dans une affectation, un print ou un return, valide dans tous les contextes d’expression

1 : Correspondance basique sur opérateurs de caractères (motif OU logique)

void main() {
  const slash = 47, star = 42, comma = 44;
  int charCode = 42;

  final token = switch (charCode) {
    slash || star => "Opérateur",
    comma => "Ponctuation",
    _ => "Caractère invalide"
  };
  print(token);
}
Langage du code : Dart (dart)

Résultat d’exécution

Opérateur

Cet exemple définit des constantes correspondant aux codes ASCII de trois symboles, puis teste la variable charCode pour classifier le caractère comme opérateur, ponctuation ou symbole inconnu.

2 : Expression switch associée au garde when

void main() {
  int age = 22;
  String level = switch (age) {
    int a when a < 18 => "Mineur",
    int a when a < 30 => "Jeune adulte",
    _ => "Adulte"
  };
  print(level);
}Langage du code : Dart (dart)

Résultat d’exécution

Jeune adulte

3 : Utilisation directe de l’expression switch dans le return d’une fonction

void main() {
  print(getDesc(3));
}

String getDesc(int num) => switch (num) {
  1 => "Un",
  2 => "Deux",
  _ => "Autre nombre"
};
Langage du code : Dart (dart)

Résultat d’exécution

Autre nombre

Attention : ici switch est une expression, et getDesc est une fonction fléchée. La fonction fléchée est une syntaxe propre à Dart absente des autres langages de type C.

V. Vérification d’exhaustivité (Exhaustiveness Checking)

Erreur de compilation si des valeurs d’entrée n’ont pas de case correspondante ; le compilateur impose de compléter tous les cas. Les classes sealed et les enums prennent nativement en charge la vérification exhaustive sans recours à _ ou default.

1 : Erreur de non-exhaustivité sur booléen nullable (commentez/décommentez pour voir l’erreur)

void main() {
  bool? nullableBool = null;
  // Décommenter le code ci-dessous provoque une erreur de compilation : absence de case pour null et pas de fallback _/default
  /*
  switch (nullableBool) {
    case true:
      print("Vrai");
    case false:
      print("Faux");
  }
  */
  // Correction : ajouter un case null ou un fallback _
  switch (nullableBool) {
    case true:
      print("Vrai");
    case false:
      print("Faux");
    case null:
      print("Valeur nulle");
  }
}Langage du code : PHP (php)

Résultat d’exécution

Valeur nulle

2 : Classe sealed (scellée)

Type de donnée algébrique qui impose une correspondance exhaustive

import 'dart:math' as math;

// Classe sealed : les sous-classes ne peuvent être définies que dans ce fichier
sealed class Shape {}

// Sous-classe Carré : longueur du côté
class Square implements Shape {
  final double length;
  Square(this.length);
}

//Sous-classe Cercle : rayon
class Circle implements Shape {
  final double radius;
  Circle(this.radius);
}

// Fonction fléchée qui calcule l’aire par correspondance switch sur l’objet sous-classe reçu
double calculateArea(Shape shape) => switch (shape) {
  Square(length: var l) => l * l,
  Circle(radius: var r) => math.pi * r * r
  // Ajouter une nouvelle sous-classe de Shape provoque une erreur de compilation signalant un case manquant
};

void main() {
  final Shape circle = Circle(5);
  print(calculateArea(circle));
  final Shape square = Square(4);
  print(calculateArea(square));
}
Langage du code : Dart (dart)

Résultat d’exécution

78.53981633974483
16.0Langage du code : CSS (css)

3 : Correspondance exhaustive sur enum

Pas besoin du marqueur de secours underscore _

void main() {
  final Animal animal = Animal.cat;
  String name = switch (animal) {
    Animal.dog => "Chien",
    Animal.cat => "Chat"
  };
  print(name);
}

enum Animal { dog, cat }
Langage du code : Dart (dart)

Sortie : Chat

Les enums ont un ensemble fini et fixe de valeurs, donc aucun fallback n’est requis.

VI. Gardes when

Fonctionnel avec if-case, instructions switch et expressions switch

Rôle du when : ajouter un contrôle booléen après validation du motif. Si le garde renvoie false, on passe à la branche suivante sans quitter le switch.

1. if-case + when

void main() {
  List<int> arr = [10, 20];
  if (arr case [int x, int y] when x + y > 20) {
    print("La somme des deux nombres dépasse 20");
  }
}Langage du code : Dart (dart)
La somme des deux nombres dépasse 20

On vérifie d’abord que c’est une liste de deux entiers, puis le when contrôle si leur somme est supérieure à 20.

2. Instruction switch + when

void main() {
  int num = 15;
  switch(num) {
    case int n when n % 2 == 0:
      print("Nombre pair");
    case int n when n % 2 != 0:
      print("Nombre impair");
  }
}
Langage du code : PHP (php)

Sortie : Nombre impair

Vérifie d’abord le type entier, puis exécute la condition du when.

3. Expression switch + when

void main() {
  int num = 15;
  String res = switch(num) {
    int n when n % 2 == 0 => "Nombre pair",
    _ => "Nombre impair"
  };
  print(res);
}
Langage du code : PHP (php)

Laisser un commentaire

Votre adresse e-mail ne sera pas publiée. Les champs obligatoires sont indiqués avec *