Pourquoi Dart
Flutter, le framework de Google pour créer des applications iOS, Android, web et bureau à partir d’un seul code, s’écrit en Dart. Dart ressemble à JavaScript, Java ou C# : si vous connaissez les bases de la programmation (variables, conditions, boucles, fonctions), vous le lirez vite.
Pour essayer sans rien installer, utilisez DartPad (dartpad.dev) dans le navigateur. Pour développer, installez le SDK Flutter (il inclut Dart) et vérifiez l’installation avec flutter doctor.
void main() {
print('Bonjour Flutter');
}
Tout programme commence par la fonction main. Les instructions se terminent par ;.
Variables et types
var ville = 'Lyon'; // type inféré : String
int quantite = 3;
double prix = 19.9;
bool enStock = true;
final dateCommande = DateTime.now(); // ne peut plus être réaffectée
const tauxTva = 0.2; // connue à la compilation
var: le type est déduit de la valeur et ne change plus (ville = 3est une erreur).final: la variable reçoit une valeur une seule fois, éventuellement calculée à l’exécution.const: la valeur est connue à la compilation ; Flutter s’en sert pour réutiliser des widgets identiques.
Les chaînes s’écrivent entre apostrophes ou guillemets et s’interpolent : 'Total : $quantite articles', 'TTC : ${prix * 1.2}'.
La sûreté vis-à-vis de null
Par défaut, une variable ne peut pas valoir null. Pour l’autoriser, on ajoute ? au type :
String nom = 'Léa'; // jamais null
String? telephone; // peut être null (vaut null ici)
print(telephone?.length); // null : ?. n'appelle rien si la valeur est null
print(telephone ?? 'non renseigné'); // ?? fournit une valeur de repli
int longueur = telephone!.length; // ! : « je garantis que ce n'est pas null » — plante sinon
Le compilateur refuse telephone.length sans précaution : la plupart des erreurs « null » sont détectées avant l’exécution. Évitez ! sauf quand vous êtes certain de la valeur ; une vérification if (telephone != null) permet ensuite d’utiliser telephone comme un String.
Fonctions et paramètres nommés
double prixTtc(double ht, {double taux = 0.2}) => ht * (1 + taux);
String etiquette({required String nom, required double prix, bool promo = false}) {
return promo ? '$nom (promo) : ${prix.toStringAsFixed(2)} €' : '$nom : ${prix.toStringAsFixed(2)} €';
}
void main() {
print(prixTtc(100)); // 120.0
print(etiquette(nom: 'Casque', prix: 39)); // Casque : 39.00 €
}
Les paramètres nommés, entre accolades, s’appellent par leur nom ; required les rend obligatoires. Flutter les utilise partout : Text('Bonjour', style: …), Padding(padding: …, child: …). La flèche => abrège une fonction qui renvoie une seule expression.
Classes
class Produit {
final String nom;
final double prix;
final int stock;
const Produit({required this.nom, required this.prix, this.stock = 0});
bool get disponible => stock > 0; // accesseur calculé
@override
String toString() => 'Produit($nom, $prix)';
}
final casque = Produit(nom: 'Casque', prix: 39, stock: 4);
print(casque.disponible); // true
this.nom dans les paramètres du constructeur initialise directement le champ. Des champs final et un constructeur const rendent l’objet immuable, ce qui est la norme pour les données en Flutter.
Collections
final produits = [
Produit(nom: 'Casque', prix: 39, stock: 4),
Produit(nom: 'Clavier', prix: 59),
];
final noms = produits.where((p) => p.disponible).map((p) => p.nom).toList(); // [Casque]
final stocks = <String, int>{'Casque': 4, 'Clavier': 0}; // Map
print(stocks['Casque']); // 4 ; une clé absente donne null
where filtre, map transforme ; tous deux renvoient un Iterable paresseux, que toList() convertit en liste.
L’asynchrone : Future, async, await
Une opération longue (réseau, fichier) renvoie un Future : une valeur disponible plus tard.
Future<String> chargerClient(int id) async {
await Future.delayed(const Duration(milliseconds: 300)); // simule le réseau
if (id <= 0) throw ArgumentError('Identifiant invalide');
return 'Client $id';
}
Future<void> main() async {
try {
print(await chargerClient(7)); // Client 7
await chargerClient(0);
} catch (e) {
print('Erreur : $e');
}
}
await suspend la fonction async sans bloquer l’interface, et try/catch capture les erreurs. Vous retrouverez exactement ce modèle pour les appels d’API.
À retenir
var,final,const; types non nuls par défaut,?,?.,??,!avec prudence.- Paramètres nommés
{required …}, classes immuables avecfinaletconst. where/map/toList,Future+async/await+try/catch.
Exercices
Les solutions et les tests restent sur le serveur. Dans l'espace étudiant, ton code est exécuté et corrigé, et le tuteur donne des indices avant la solution.
Produits disponibles et total TTC
Dans DartPad (ou avec
dart runen local), écrivez une classeProduitavec les champsfinal String nom,final double prixetfinal int? stock, un constructeurconst Produit(this.nom, this.prix, {this.stock})et une méthodedouble prixTtc([double taux = 0.2]).Dans
main, créez cette liste :nom,prix,stock Casque,40,3 Clavier,50,(aucun) Souris,25,0Puis affichez, avec deux
print:- la liste des noms des produits dont le stock est strictement positif (un stock absent compte pour 0) ;
- le total TTC des trois produits avec
toStringAsFixed(2).
- Le programme compile sans avertissement de null safety
- Le stock absent est traité avec ?? 0 et non avec !
- La sortie comporte exactement deux lignes
Ordre d'exécution asynchrone
Exécutez ce programme dans DartPad, puis complétez la fonction
chargerNompour qu’elle attende 100 ms, lèveException('introuvable')siid == 0et renvoie'Client $id'sinon.Future<String> chargerNom(int id) async { // à compléter } Future<void> main() async { print('Début'); final nom = await chargerNom(7); print(nom); try { await chargerNom(0); } catch (e) { print('Erreur : $e'); } print('Fin'); }- chargerNom utilise await Future.delayed(const Duration(milliseconds: 100))
- L'erreur est levée avec throw Exception('introuvable')
- La sortie comporte quatre lignes dans l'ordre attendu
Opérateurs de null safety
Que affiche ce code ?
String? ville; print(ville?.length ?? 0);- null
- 0
- Une erreur à l'exécution
- Une erreur de compilation
Quiz de fin de leçon
Quelle déclaration accepte la valeur null ?
- String nom;
- String? nom;
- final String nom = '';
Comment rend-on un paramètre nommé obligatoire ?
- Avec le mot-clé required
- Avec !
- En le plaçant en premier
Que renvoie une fonction marquée async qui renvoie un int ?
- int
- Future<int>
- Stream<int>
La suite du cours
- Widgets et mise en page18 min
- État et interactions20 min
- Réseau et données JSON18 min
- Préparer la publication d'une application Flutter16 min