Вы находитесь на странице: 1из 151

Dart documentation

Language samples
A brief, example-based introduction to the Dart language.

Language tour
A more thorough (yet still example-based) introduction to the Dart language.

Dart efficace
Best practices for building consistent, maintainable, efficient Dart code.

Library tour
An example-based introduction to the major features in the Dart SDK's core
libraries.

1
A tour of the Dart language
Contents

 Un programme de base Dart


 Concepts importants
 Mots clés
 Les variables
o Valeur par défaut
o Finale et const
 Types intégrés
o Les nombres
o Les chaînes de caractères
o Les booléens
o Les listes
o Sets
o Maps
o Les runes
o Les symboles
 Les fonctions
o Les paramètres optionnels
o La fonction main()
o Transmission de fonction
o Fonctions anonymes
o Portée lexicale
o Closures lexicales
o Test d'égalité de fonctions
o Retourner des valeurs
 Les opérateurs
o Opérateurs arithmétiques
o Égalité et opérateurs relationnels
o Opérateurs de test de type
o Opérateurs d'assignation
o Opérateurs logiques
o Opérateurs binaires et de décalage
o Expressions conditionnelles
o Notation en cascade (..)
o Les autres opérateurs
 Instructions de contrôle de flux
o If et else
o Les boucles For
o Les boucle While et do-while
o Break et continue
o Switch et case
o Assert

2
 Les exceptions
o Throw
o Catch
o Finally
 Les Classes
o Utilisation des membres de la classe
o Utiliser des constructeurs
o Obtenir le type d'un objet
o Variables d'instance
o Les constructeurs
o Les méthodes
o Classes abstraites
o Interfaces implicites
o Héritage de classe
o Les types énumérés
o Ajout de fonctionnalités à une classe: mixins
o Variables et méthodes de classe
 Les génériques
o Pourquoi utiliser des génériques?
o Utiliser une collection de littéraux
o Utiliser des types paramétrés avec les constructeurs
o Collections génériques et types qu'elles contiennent
o Restreindre le type paramétré
o Utiliser des méthodes génériques
 Bibliothèques et visibilité
o Utiliser les librairies
o Implémentation de librairies
 Asynchronisme
o Gestion des Futures
o Déclarer des fonctions async
o Traitement des flux
 Les générateurs
 Les classes appelables
 Isolats
 Typedefs
 Métadonnées
 Commentaires
o Commentaires sur une seule ligne
o Commentaires multilignes
o Commentaires de la documentation
 Résumé

3
Cette page vous montre comment utiliser chaque fonction majeure de Dart,
depuis les variables et opérateurs jusqu'aux classes et bibliothèques, avec
l'hypothèse que vous savez déjà programmer dans un autre langage.

To learn more about Dart’s core libraries, see the library tour. Chaque fois que
vous voulez plus de détails sur une fonctionnalité du langage,
consulter Spécification du langage Dart.

Astuce: Vous pouvez jouer avec la plupart des fonctionnalités linguistiques de


Dart à l'aide de DartPad (en savoir plus).

Ouvrir un DartPad

Un programme de base Dart


Le code suivant utilise de nombreuses fonctionnalités de base de Dart:

// Define a function.
printInteger(int aNumber) {
print('The number is $aNumber.'); // Print to console.
}

// This is where the app starts executing.


main() {
var number = 42; // Declare and initialize a variable.
printInteger(number); // Call a function.
}

Voici ce que ce programme utilise qui s’applique à toutes (ou presque) les
applications Dart:

// Ceci est un commentaire.

Un commentaire d'une seule ligne. Dart prend également en charge les


commentaires multiligne et document. Pour plus de détails,
voir commentaires .
int

Un type de variable. il existes d'autres types


intégrés comme String, List, et bool.
42

Un nombre littéral. Les littéraux numériques sont une sorte de constante


de compilation.

4
print()

Un moyen pratique d’afficher les résultats.

'...'(ou"...")

Une chaîne de caractères littérale.

$variableName (ou ${expression})

Interpolation de chaîne: permet de remplacer dans une chaîne de


caractères une variable par sa valeur. Pour plus d'informations, voir Les
chaînes de caractères.
main()

Une fonction, obligatoire, qui est la première instruction exécutée


lorsque l'application démarre. Pour plus d'informations, voir La fonction
main().
var

Un moyen de déclarer une variable sans spécifier son type.

Remarque: Le code de ce site suit les conventions du Guide de style de Dart.

Concepts importants
Tout au long de votre apprentissage du langage Dart, tâchez de conservez ce
qui suit en tête:

 Tout ce que vous pouvez placer dans une variable est un objetet
chaque objet est une instance d'une class. Les nombres pairs, les
fonctions et nullsont des objets. Tous les objets héritent de la
class Object.
 Bien que Dart soit fortement typé, les annotations de type sont
facultatives parce que Dart peut déduire des types. Dans le code ci-
dessus, la variable number est reconnue comme étant de type int.
Quand vous voulez dire explicitement indiquer qu'aucun type n'est
attendu, utiliser le type spécial dynamic.
 Dart supporte les types génériques, comme List<int>(une liste
d'entiers) ou List<dynamic>(une liste d'objets de tout type).
 Dart prend en charge les fonctions de niveau supérieur (telles
que main()), aussi bien que fonctions liées à une classe ou à un objet
( staticet instance methods, respectivement). Vous pouvez également
créer des fonctions dans les fonctions (imbriquée ou fonction locale).
5
 De même, Dart prend en charge les variables globales, ainsi que des
variables lié à une classe ou à un objet (variables statiques et
d'instance). Exemple les variables sont parfois appelées champs ou
propriétés.
 Contrairement à Java, Dart ne reconnait pas les mots-
clés public, protected, et private. Si un identifiant commence par un trait
de soulignement (_), alors ils s'agit d'une variable ou méthode privée à
sa bibliothèque. Pour plus de détails, voir Bibliothèques et visibilité .
 Les Identifiants peut commencer par une lettre ou un trait de
soulignement (_), suivi de n'importe quelle combinaison de caractères,
de chiffres et traits de soulignement (_).
 Dart gère les expressions (qui ont des valeurs d'exécution) et
les instructions (qui n'en n'ont pas). Par exemple, l'expression
conditionnelle condition ? expr1 : expr2 prend la une valeur
de expr1 ou expr2. Par contre l'instruction if-else statement, n'a aucune
valeur. Une instruction contient souvent une ou plusieurs expressions,
mais une expression ne peut pas contenir directement une instruction.
 Les outils de Dart peuvent signaler deux types de problèmes: les
avertissements (warnings) et les erreurs (errors). Les avertissements ne
sont que des indications que votre code pourrait ne pas fonctionner,
mais ils n’empêchent pas votre programme de s’exécuter. Les erreurs
peuvent être soit au moment de la compilation ou de l'exécution. Une
erreur de compilation empêche le code d'exécuter du tout; une erreur
d'exécution entraîne la levée d'une exception pendant l'exécution du
code.

Keywords
Le tableau suivant répertorie les mots que le langage Dart traite spécialement.

abstract 2 dynamic 2 implements 2 show 1

as 2 else import 2 static 2

assert enum in super

async 1 export 2 interface 2 switch

await 3 extends is sync 1

break external 2 library 2 this

case factory 2 mixin 2 throw

6
catch false new true

class final null try

const finally on 1 typedef 2

continue for operator 2 var

covariant 2 Function 2 part 2 void

default get 2 rethrow while

deferred 2 hide 1 return with

do if set 2 yield 3

Évitez d’utiliser ces mots comme identifiants. Toutefois, si nécessaire, les


mots-clés marqués avec des indices supérieurs peuvent être des
identificateurs:

 Mots indicés 1 sont des mots-clés contextuels , qui ont un sens que
dans des endroits spécifiques. Ce sont des identifiants valides partout.
 Mots indicés 2 sont des identifiants intégrés . Pour simplifier la
conversion du code JavaScript en Dart, ces mots-clés sont des
identifiants valables dans la plupart des endroits, mais ils ne peuvent
pas être utilisés comme noms de classe ou de type, ni comme préfixes
d’importation.
 Mots indicés 3sont des mots nouveaux, réservés et liés à au support
asynchrone qui a été ajouté après la sortie de Dart 1.0. Vous ne pouvez
pas utiliser await ou yieldcomme identifiant dans tout corps de fonction
marqué avec async, async*, ou sync*.

Tous les autres mots du tableau sont des mots réservés , qui ne peuvent pas
être utilisés.

Variables
Voici un exemple de création et d’initialisation d’une variable:

var name = 'Bob';

Les variables stockent des références. La variable appelée namecontient une


référence à un objet String contenant la valeur "Bob".

7
Le type de la variable nameest convertie par déduction en String, mais vous
pouvez changer ce type en le spécifiant. Si un objet n'est pas limité à un seul
type, spécifiez le type Object ou dynamic conformément directives de
conception.

dynamic name = 'Bob';

Une autre option consiste à déclarer explicitement le type qui serait déduit:

String name = 'Bob';

Remarque: Cette page suit la recommandation de style d'utilisation var, plutôt


que des annotations de type, pour les variables locales.

Default value
Les variables non initialisées ont une valeur initiale null. Même variables avec
des types numériques sont initialement nuls, parce que les nombres - comme
tout dans Dart - sont des objets.

int lineCount;
assert(lineCount == null);

Remarque: Production code ignores the assert() call. During development, on


the other hand, assert(condition) throws an exception if condition is false. For
details, see Assert.

Final and const


Si vous n’avez jamais l’intention de changer une variable, utilisez le mot
clé final ou const. Ce mot clé peut se substituer à var ou précéder le type.
Une variable finale peut être définie juste une fois; une variable const est une
constante au moment de la compilation. (Variables constantes sont
implicitement final.) Une variable globale finale ou de classe est initialisée la
première fois qu'elle est utilisée.

Remarque: Les variables d'instance peuvent être final mais pas const. Les
variables d'instance finales doivent être initialisées avant l’exécution du
constructeur - à la déclaration de la variable, par un paramètre constructeur,
ou dans le constructeur l'initialisation par liste.

Voici un exemple de création et de définition d’une variable finale:

final name = 'Bob'; // Without a type annotation


final String nickname = 'Bobby';

8
Vous ne pouvez pas changer la valeur d’une variable finale:

name = 'Alice'; // Error: a final variable can only be set


once.

Utilisez const pour les variables que vous voulez qui peuvent être compilé
comme des constantes. Si la variable const est au niveau de la classe,
marquez-la static const. Où vous déclarez la variable, définissez la valeur qui
puisse être compilé en tant que constante comme un nombre ou une chaîne
littérale, une autre variable const, ou le résultat d'une opération arithmétique
sur des nombres constants:

const bar = 1000000; // Unit of pressure (dynes/cm2)


const double atm = 1.01325 * bar; // Standard atmosphere

Le mot clé const n'est pas juste utilisée pour déclarer des variables
constantes. Vous pouvez également l'utiliser pour créer
des valeursconstantes, ainsi que pour déclarer des constructeurs créant des
valeurs constantes. Toute variable peut avoir une valeur constante.

var foo = const [];


final bar = const [];
const baz = []; // Equivalent to `const []`

Vous pouvez omettre const dans l'instruction d'initialisation si vous avez


mentionné const lors de la déclaration, comme pour baz au dessus de. Pour
plus de détails, voir NE PAS utiliser const de manière redondante .

Vous pouvez changer la valeur d'une variable non finale, non constante,
même si elle avait une valeur const:

foo = [1, 2, 3]; // Was const []

Vous ne pouvez pas changer la valeur d’une variable const:

baz = [42]; // Error: Constant variables can't be assigned


a value.

Pour plus d'informations sur l'utilisation de const pour créer des valeurs
constantes, voir Les listes, Les tableaux associatifs, et Les classes .

9
Built-in types
Le langage Dart prend en charge les types suivants:

 les nombres
 les chaînes de caractères
 les booléens
 les listes (également appelées arrays)
 sets
 les tableaux associatifs
 les runes (pour exprimer des caractères Unicode dans une chaîne)
 les symboles

Vous pouvez initialiser un objet de l’un de ces types spéciaux en utilisant un


littéral. Par exemple, 'this is a string' is a string literal, and true is a
boolean literal.

Because every variable in Dart refers to an object—an instance of a class—


you can usually use constructors to initialize variables. Some of the built-in
types have their own constructors. For example, you can use
the Map() constructor to create a map.

Numbers
Dart numbers come in two flavors:

int

Les valeurs entières ne dépassant pas 64 bits, en fonction de la plate-


forme. Sur la Dart VM, les valeurs peuvent aller de: -2 63 à 263- 1. Dart
compilée en JavaScript utilise JavaScript numbers,permettant des
valeurs de -2 53 à 2 53 - 1.

double

Nombres à virgule flottante 64 bits (double précision), comme spécifié


par la norme IEEE 754.

Les int et les double sont des sous type de num.Le type num inclut des
opérateurs de base tels que +, -, / et *, et c'est aussi où vous
trouverez abs(), ceil(), et floor(), entre autres méthodes. (Les opérateurs
binaires, tels que >>, sont définis dans la class intuniquement.) Si num et ses
sous-types ne correspondent pas à ce que vous recherchez, la
bibliothèque dart:math le pourrait peut-être.

10
Les entiers sont des nombres sans virgule décimale. Voici quelques exemples
de définir des littéraux entiers:

var x = 1;
var hex = 0xDEADBEEF;

If a number includes a decimal, it is a double. Here are some examples of


defining double literals:

var y = 1.1;
var exponents = 1.42e5;

As of Dart 2.1, integer literals are automatically converted to doubles when


necessary:

double z = 1; // Equivalent to double z = 1.0.

Note de version: Avant Dart 2.1, l’utilisation d’un littéral entier à la place d'un double était
une erreur.

Voici comment transformer une chaîne en nombre, ou inversement:

// String -> int


var one = int.parse('1');
assert(one == 1);

// String -> double


var onePointOne = double.parse('1.1');
assert(onePointOne == 1.1);

// int -> String


String oneAsString = 1.toString();
assert(oneAsString == '1');

// double -> String


String piAsString = 3.14159.toStringAsFixed(2);
assert(piAsString == '3.14');

Le type int permet le décalage binaire traditionnel (<<, >>), ainsi que les
opérateurs ET (&) et OU (|). Par exemple:

assert((3 << 1) == 6); // 0011 << 1 == 0110


assert((3 >> 1) == 1); // 0011 >> 1 == 0001
assert((3 | 4) == 7); // 0011 | 0100 == 0111

Les nombres littérales sont des constantes à la compilation ainsi que toute
expression produite à partir de constantes à la compilation.

11
const msPerSecond = 1000;
const secondsUntilRetry = 5;
const msUntilRetry = secondsUntilRetry * msPerSecond;

Strings
Une chaîne Dart est une séquence de caractères UTF-16. Vous pouvez
utiliser soit guillemets simples ou doubles pour créer une chaîne:

var s1 = 'Single quotes work well for string literals.';


var s2 = "Double quotes work just as well.";
var s3 = 'It\'s easy to escape the string delimiter.';
var s4 = "It's even easier to use the other delimiter.";

Vous pouvez mettre la valeur d'une expression dans une chaîne en


utilisant ${expression}. Si l'expression est un identifiant, vous pouvez ignorer
les {}. Pour obtenir la chaîne correspondant à un objet, Dart appelle la
méthode de l'objet toString().

var s = 'string interpolation';

assert('Dart has $s, which is very handy.' ==


'Dart has string interpolation, ' +
'which is very handy.');
assert('That deserves all caps. ' +
'${s.toUpperCase()} is very handy!' ==
'That deserves all caps. ' +
'STRING INTERPOLATION is very handy!');

Remarque: L'appel == teste si deux objets sont équivalents. Deux les chaînes
sont équivalentes si elles contiennent la même séquence de caractères.

Vous pouvez concaténer des chaînes en les juxtaposant ou en utilisant


l'opérateur +.

var s1 = 'String '


'concatenation'
" works even over line breaks.";
assert(s1 ==
'String concatenation works even over '
'line breaks.');

var s2 = 'The + operator ' + 'works, as well.';


assert(s2 == 'The + operator works, as well.');

12
Une autre façon de créer une chaîne multiligne: utilisez un guillemet triple
avec guillemets simples ou doubles:

var s1 = '''
You can create
multi-line strings like this one.
''';

var s2 = """This is also a


multi-line string.""";

Vous pouvez créer une chaîne "brute" en la préfixant avec r:

var s = r'In a raw string, not even \n gets special


treatment.';

Voir Les runes pour plus de détails sur la façon d'exprimer les caractères
Unicode dans une chaîne.

Les chaînes littérales sont des constantes à la compilation ainsi que toute
expression produite à partir de constantes à la compilation.

// These work in a const string.


const aConstNum = 0;
const aConstBool = true;
const aConstString = 'a constant string';

// These do NOT work in a const string.


var aNum = 0;
var aBool = true;
var aString = 'a string';
const aConstList = [1, 2, 3];

const validConstString = '$aConstNum $aConstBool


$aConstString';
// const invalidConstString = '$aNum $aBool $aString
$aConstList';

Pour plus d'informations sur l'utilisation de chaînes, voir Chaînes et


expressions régulières .

13
Les booléens
Pour représenter les valeurs booléennes, Dart a un type nommé bool.
Seulement deux les objets ont le type bool: les littéraux booléens true et false,
qui sont également des constantes à la compilation.

La sécurité de type Dart signifie que vous ne pouvez pas utiliser de code
comme if (nonbooleanValue) ou assert (nonbooleanValue). Au lieu de cela,
vérifiez explicitement les valeurs, comme ceci:

// Check for an empty string.


var fullName = '';
assert(fullName.isEmpty);

// Check for zero.


var hitPoints = 0;
assert(hitPoints <= 0);

// Check for null.


var unicorn;
assert(unicorn == null);

// Check for NaN.


var iMeantToDoThis = 0 / 0;
assert(iMeantToDoThis.isNaN);

Lists
Peut-être la collection la plus commune dans presque tous les langages de
programmation est le tableau, ou groupe ordonné d'objets. Dans Dart, les
tableaux sont des objets List, de sorte que la plupart des gens les
appellent listes.

Dart list literals look like JavaScript array literals. Here’s a simple Dart list:

var list = [1, 2, 3];

Remarque: Dart infers that list est de type List<int>. Si vous essayez d’ajouter des objets
non-entiers à cette liste, l'analyseur ou le moteur d'exécution génère une erreur. Pour plus
d'informations, lisez la page concernant la déduction de type

Les listes conserve les informations de façon ordonnée, où 0 est l'index du


premier élément et list.length - 1est l'index du dernier élément. Vous
pouvez obtenir une liste et fait référence aux éléments de la liste comme vous
le feriez dans JavaScript:

14
var list = [1, 2, 3];
assert(list.length == 3);
assert(list[1] == 2);

list[1] = 1;
assert(list[1] == 1);

Pour créer une liste qui est une constante de compilation, ajouter constavant la
liste littérale:

var constantList = const [1, 2, 3];


// constantList[1] = 1; // Uncommenting this causes an
error.

Dart 2.3 introduced the spread operator (...) and the null-aware spread
operator (...?), which provide a concise way to insert multiple elements into a
collection.

For example, you can use the spread operator (...) to insert all the elements
of a list into another list:

var list = [1, 2, 3];


var list2 = [0, ...list];
assert(list2.length == 4);

If the expression to the right of the spread operator might be null, you can
avoid exceptions by using a null-aware spread operator (...?):

var list;
var list2 = [0, ...?list];
assert(list2.length == 1);

For more details and examples of using the spread operator, see the spread
operator proposal.

Dart 2.3 also introduced collection if et collection for, which you can use to
build collections using conditionals (if) and repetition (for).

Here’s an example of using collection if to create a list with three or four


items in it:

var nav = [
'Home',
'Furniture',
'Plants',
if (promoActive) 'Outlet'
];

15
Here’s an example of using collection for to manipulate the items of a list
before adding them to another list:

var listOfInts = [1, 2, 3];


var listOfStrings = [
'#0',
for (var i in listOfInts) '#$i'
];
assert(listOfStrings[1] == '#1');

For more details and examples of using collection if and for, see the control
flow collections proposal.

Le type List contient de nombreuses méthodes pratiques pour manipuler les


listes. Pour plus informations sur les listes, voir Les génériques et Les
collections .

Sets
A set in Dart is an unordered collection of unique items. Dart support for sets is
provided by set literals and the Set.

Version note: Although the Set type has always been a core part of Dart, set literals were
introduced in Dart 2.2.

Here is a simple Dart set, created using a set literal:

var halogens = {'fluorine', 'chlorine', 'bromine',


'iodine', 'astatine'};

Remarque: Dart infers that halogens a le type Set<String>. If you try to add the wrong
type of value to the set, the analyzer or runtime raises an error. For more information, read
about déduction de type

To create an empty set, use {} preceded by a type argument, or assign {} to a


variable of type Set:

var names = <String>{};


// Set<String> names = {}; // This works, too.
// var names = {}; // Creates a map, not a set.

Set or map? The syntax for map literals is similar to that for set literals. Because map literals
came first, {} defaults to the Maptype. If you forget the type annotation on {} or the variable
it’s assigned to, then Dart creates an object of type Map<dynamic, dynamic>.

Add items to an existing set using the add() ou addAll() methods:

16
var elements = <String>{};
elements.add('fluorine');
elements.addAll(halogens);

Utilisez .length to get the number of items in the set:

var elements = <String>{};


elements.add('fluorine');
elements.addAll(halogens);
assert(elements.length == 5);

To create a set that’s a compile-time constant, add const before the set literal:

final constantSet = const {


'fluorine',
'chlorine',
'bromine',
'iodine',
'astatine',
};
// constantSet.add('helium'); // Uncommenting this causes
an error.

As of Dart 2.3, sets support spread operators (... et ...?) and collection ifs
and fors, just like lists do. For more information, see the list spread
operator et list collection operator discussions.

For more information about sets, see Les génériques et Sets.

Les tableaux associatifs


En général, un tableau associatif est un objet qui associe des clés à des
valeurs. Les clés et les valeurs peuvent être un objet de n'importe quel type.
Chaque clé est unique, mais vous pouvez utiliser la même valeur plusieurs
fois. Pour créer un tableau associatif en Dart utilisez le mot clé Map type.

Voici quelques tableaux associatifs simples en Dart, créées à l'aide de


littéraux:

var gifts = {
// Key: Value
'first': 'partridge',
'second': 'turtledoves',
'fifth': 'golden rings'
};

17
var nobleGases = {
2: 'helium',
10: 'neon',
18: 'argon',
};

Remarque: Dart infers that gifts a le type Map<String, String> et nobleGases has the
type Map<int, String>. Si vous essayez d'ajouter le mauvais type de valeur au tableau,
l'analyseur ou le moteur d'exécution génère une erreur. Pour plus d'informations, lisez à
propos de type inference.

Vous pouvez créer les mêmes en utilisant l'un des constructeurs de l'objet
Map:

var gifts = Map();


gifts['first'] = 'partridge';
gifts['second'] = 'turtledoves';
gifts['fifth'] = 'golden rings';

var nobleGases = Map();


nobleGases[2] = 'helium';
nobleGases[10] = 'neon';
nobleGases[18] = 'argon';

Remarque: Vous pourriez vous attendre à voir new Map() au lieu de juste Map(). À partir de
Dart 2, le mot clé new est facultatif. Pour plus de détails, voir Utiliser des constructeurs .

Ajoutez un couple clé-valeur à un tableau associatif, comme vous le feriez


dans JavaScript:

var gifts = {'first': 'partridge'};


gifts['fourth'] = 'calling birds'; // Add a key-value pair

Récupérez une valeur d'un tableau associatif de la même manière qu'en


JavaScript:

var gifts = {'first': 'partridge'};


assert(gifts['first'] == 'partridge');

Si vous recherchez une clé qui ne figure pas dans le tableau, vous obtenez
une valeur null en retour:

var gifts = {'first': 'partridge'};


assert(gifts['fifth'] == null);

Utilisez .lengthpour obtenir le nombre de paires clé-valeur dans la carte:

18
var gifts = {'first': 'partridge'};
gifts['fourth'] = 'calling birds';
assert(gifts.length == 2);

Pour créer un tableau qui soit qui est une constante de compilation,
ajouter const avant déclaration littérale du tableau associatif:

final constantMap = const {


2: 'helium',
10: 'neon',
18: 'argon',
};

// constantMap[2] = 'Helium'; // Uncommenting this causes


an error.

As of Dart 2.3, maps support spread operators (... et ...?) and collection if
and for, just like lists do. For details and examples, see thespread operator
proposal and the control flow collections proposal.

Pour plus d'informations à propos des tableaux associatif,


voir Genericset Maps.

Runes
Dans Dart, les runes sont les caractères UTF-32 d'une chaîne.

Unicode définit une valeur numérique unique pour chaque lettre, chiffre,
symbole utilisé dans tous les systèmes d’écriture du monde. Parce qu'une
chaîne Dart est une séquence de caractères UTF-16, l'expression de valeurs
Unicode 32 bits dans une chaîne nécessite syntaxe spéciale.

La manière habituelle d’exprimer un caractères Unicode est la


suivante: \uXXXX, où XXXX est une valeur hexadécimale à 4 chiffres. Par
exemple, le caractère du coeur (♥) est \u2665. Pour spécifier plus ou moins de
4 chiffres hexadécimaux, Placez la valeur entre accolades. Par exemple,
l’émoji qui rit (😆) est \u{1f600}.

La classe String a plusieurs propriétés que vous pouvez utiliser pour extraire
des informations sur les runes. les propritétés codeUnitAtet codeUnit retournent
un caractère 16 bits. Utilisez la propriété runes pour obtenir les runes d'une
chaîne.

19
L’exemple suivant illustre la relation entre les runes, caractères 16 bits et

caractères 32 bits. Cliquez sur le bouton Exécuter pour voir les runes en
action.

Remarque: Soyez prudent lorsque vous manipulez des runes à l'aide des
fonctions de l'objet List. Cette approche peut facilement échouer, en fonction
de la langue, du jeu de caractères et de l'opération. Pour plus d'informations,
voir Comment inverser une chaîne dans Dart? sur Stack Overflow.

Symbols
Un objet Symbol représente un opérateur, un identifiant ou une classe déclaré
dans un programme Dart. Vous n’aura peut-être jamais besoin d’utiliser des
symboles, mais ils sont d’une valeur inestimable pour les API qui doivent faire
référence aux identifiants par leur nom. En Dart on utilise les symboles pour
savoir par exemple si la méthode d'un classe existe. La classe (et non l'object)
et la méthode dispose tous les deux d'un symbole unique.

Pour obtenir le symbole d’un identifiant, utilisez #suivi de l'identifiant:

#radix
#bar

Les littéraux de symboles sont des constantes à la compilation.

Functions
Dart est un vrai langage orienté objet, donc même les fonctions sont des
objets et avoir un type, Function.Cela signifie que les fonctions peuvent être
assignées à des variables ou transmises en tant qu'arguments à d'autres
fonctions. Vous pouvez également appeler une instance d'une classe Dart
comme si c'était une fonction. Pour plus de détails, voir Les classes
appelables.

Voici un exemple de mise en œuvre d’une fonction:

bool isNoble(int atomicNumber) {


return _nobleGases[atomicNumber] != null;
}

Bien qu'optionnelle, Dart recommande une annotations de type pour les API
publiques, la fonction fonctionne toujours si vous omettez les types:

isNoble(atomicNumber) {

20
return _nobleGases[atomicNumber] != null;
}

Pour les fonctions contenant une seule expression, vous pouvez utiliser un
raccourci syntaxe:

bool isNoble(int atomicNumber) =>


_nobleGases[atomicNumber] != null;

La syntaxe => expr est un raccourci pour { return expr; } La notation => est
parfois appelée syntaxe fléchée.

Remarque: Only an expression - et pas une instruction—can appear between the arrow (=>)
and the semicolon (;). For example, you can’t put an if statement ici, mais vous pouvez
utiliser une conditional expression.

A function can have two types of parameters: obligatoire et optional. The


required parameters are listed first, followed by any optional parameters.
Optional parameters can be named ou positional.

Remarque: Some APIs — notably Flutter: widget constructors — use only named
parameters, even for parameters that are mandatory. See the next section for details.

Les paramètres optionnels


Optional parameters can be either named or positional, but not both.

Named parameters
Lors de l'appel d'une fonction, vous pouvez spécifier des paramètres nommés
à l'aide de paramName: value. Par exemple:

enableFlags(bold: true, hidden: false);

Lorsque vous définissez une fonction, utilisez {param1, param2, …} pour


spécifier les paramètres nommés:

/// Sets the [bold] and [hidden] flags ...


void enableFlags({bool bold, bool hidden}) {...}

Although named parameters are a kind of optional parameter, you can


annotate them with @required to indicate that the parameter is mandatory —
that users must provide a value for the parameter. For example:

const Scrollbar({Key key, @required Widget child})

21
If someone tries to create a Scrollbar without specifying the child argument,
then the analyzer reports an issue.

To use the @required annotation, depend on the meta package and


import package:meta/meta.dart.

Positional parameters
Encadrer des paramètres de fonction par des crochets [] les marque comme
facultatifs.

String say(String from, String msg, [String device]) {


var result = '$from says $msg';
if (device != null) {
result = '$result with a $device';
}
return result;
}

Voici un exemple d'appel de cette fonction sans le paramètre optionnel:

assert(say('Bob', 'Howdy') == 'Bob says Howdy');

Et voici un exemple d’appel de cette fonction avec le troisième paramètre:

assert(say('Bob', 'Howdy', 'smoke signal') ==


'Bob says Howdy with a smoke signal');

Valeurs par défaut d'un paramètre


Votre fonction peut utiliser = pour définir les valeurs par défaut pour les
paramètres nommés et le paramètres positionnés. Les valeurs par défaut
doivent être des constantes à la compilation. Si aucune valeur par défaut n'est
fournie, la valeur par défaut est null.

Voici un exemple de définition des valeurs par défaut pour les paramètres
nommés:

/// Sets the [bold] and [hidden] flags ...


void enableFlags({bool bold = false, bool hidden = false})
{...}

// bold will be true; hidden will be false.


enableFlags(bold: true);

22
Note de dépréciation: L'ancienne version de Dart utilisait le caractère : au
lieu de = pour définir les valeurs par défaut des paramètres nommés. La raison
en est qu'à l'origine, seul : was supported for named parameters. That support
might be deprecated, so we recommend that you d'utiliser = pour spécifier
les valeurs par défaut.

L'exemple suivant montre comment définir les valeurs par défaut pour les
paramètres positionnés:

String say(String from, String msg,


[String device = 'carrier pigeon', String mood]) {
var result = '$from says $msg';
if (device != null) {
result = '$result with a $device';
}
if (mood != null) {
result = '$result (in a $mood mood)';
}
return result;
}

assert(say('Bob', 'Howdy') ==
'Bob says Howdy with a carrier pigeon');

Vous pouvez également transmettre des listes ou des tableaux associatifs en


tant que valeurs par défaut. L’exemple suivant définit une fonction, doStuff(),
qui spécifie une liste par défaut pour le paramètre list et un tableau associatif
par défaut pour le paramètre gifts.

void doStuff(
{List<int> list = const [1, 2, 3],
Map<String, String> gifts = const {
'first': 'paper',
'second': 'cotton',
'third': 'leather'
}}) {
print('list: $list');
print('gifts: $gifts');
}

23
La fonction main()
Chaque application doit avoir une fonction de niveau supérieur main() function,
which serves as the entrypoint to the app. The main()function returns void and
has an optional List<String> parameter for arguments.

Voici un exemple de fonction main() pour une application web:

void main() {
querySelector('#sample_text_id')
..text = 'Click me!'
..onClick.listen(reverseText);
}

Remarque: L'opérateur .. qui précède le code précédent est


appelée cascade. Avec des cascades, vous pouvez effectuer plusieurs
opérations sur les membres d'un même objet.

Voici un exemple de fonction main() pour une application en ligne de


commande qui prend des arguments:

// Run the app like this: dart args.dart 1 test


void main(List<String> arguments) {
print(arguments);

assert(arguments.length == 2);
assert(int.parse(arguments[0]) == 1);
assert(arguments[1] == 'test');
}

Vous pouvez utiliser la bibliothèque args pour définir et analyser les


arguments de ligne de commande.

Transmission de fonction
Vous pouvez transmettre une fonction en tant que paramètre à une autre
fonction. Par exemple:

void printElement(int element) {


print(element);
}

var list = [1, 2, 3];

// Pass printElement as a parameter.

24
list.forEach(printElement);

Vous pouvez également affecter une fonction à une variable, telle que:

var loudify = (msg) => '!!! ${msg.toUpperCase()} !!!';


assert(loudify('hello') == '!!! HELLO !!!');

Cet exemple utilise une fonction anonyme. Plus d'informations concernant ce


sujet dans la section suivante.

Fonctions anonymes
La plupart des fonctions sont nommées, telles que main() ou printElement().
Vous pouvez également créer une fonction sans nom appelée fonction
anonyme , ou parfois lambdaou closure. Vous pouvez affecter une fonction
anonyme à une variable. Vous pouvez également l'ajouter ou la supprimer
d'une collection.

Une fonction anonyme ressemble à une fonction nommée - zéro ou plusieurs


paramètres, séparés par des virgules et des annotations de type facultatives,
entre parenthèses.

Le bloc de code qui suit contient le corps de la fonction:

([[Type] param1[, …]]) {


codeBlock;
};

L’exemple suivant définit une fonction anonyme avec un paramètre non


typé, item. La fonction est appelée pour chaque élément de la liste, imprime
une chaîne qui inclut la valeur de la liste à l'index spécifié.

var list = ['apples', 'bananas', 'oranges'];


list.forEach((item) {
print('${list.indexOf(item)}: $item');
});

Cliquez sur le bouton Exécuter pour exécuter le code.

Si la fonction ne contient qu'une seule instruction, vous pouvez la raccourcir à


l'aide de notation flèchée. Collez la ligne suivante dans DartPad et cliquez sur
Exécuter pour vérifier qu'il est fonctionnellement équivalent.

list.forEach(
(item) => print('${list.indexOf(item)}: $item'));

25
Lexical scope
Dart est un langage à portée lexicale, ce qui signifie que la portée de les
variables sont déterminées statiquement, simplement par la disposition du
code. Vous pouvez "suivre les accolades vers l'extérieur" pour voir si une
variable est dans portée.

Voici un exemple de fonctions imbriquées avec des variables définies à


chaque niveau:

bool topLevel = true;

void main() {
var insideMain = true;

void myFunction() {
var insideFunction = true;

void nestedFunction() {
var insideNestedFunction = true;

assert(topLevel);
assert(insideMain);
assert(insideFunction);
assert(insideNestedFunction);
}
}
}

Remarquez comment nestedFunction()peut utiliser des variables de tous les


niveaux, tous le chemin jusqu'au plus haut niveau.

Closures lexicales
Une closure est un objet fonction qui a accès aux variables de sa portée
lexicale, même lorsque la fonction est utilisée en dehors de sa portée
d'origine.

Les fonctions anonymes produite à partir d'un argument d'une fonction


conservent la valeur de cet argument. Dans le exemple
suivant, makeAdder() capture la variable addBy. Dès lors la fonction retournée se
souvient de addBy.

/// Returns a function that adds [addBy] to the


/// function's argument.

26
Function makeAdder(num addBy) {
return (num i) => addBy + i;
}

void main() {
// Create a function that adds 2.
var add2 = makeAdder(2);

// Create a function that adds 4.


var add4 = makeAdder(4);

assert(add2(3) == 5);
assert(add4(3) == 7);
}

Test d'égalité de fonctions


Voici un exemple de test des fonctions de niveau supérieur, des méthodes
statiques et méthodes d'instance pour l'égalité:

void foo() {} // A top-level function

class A {
static void bar() {} // A static method
void baz() {} // An instance method
}

void main() {
var x;

// Comparing top-level functions.


x = foo;
assert(foo == x);

// Comparing static methods.


x = A.bar;
assert(A.bar == x);

// Comparing instance methods.


var v = A(); // Instance #1 of A
var w = A(); // Instance #2 of A
var y = w;
x = w.baz;

// These closures refer to the same instance (#2),


// so they're equal.
assert(y.baz == x);
27
// These closures refer to different instances,
// so they're unequal.
assert(v.baz != w.baz);
}

Return values
Toutes les fonctions renvoient une valeur. Si aucune valeur de retour n'est
spécifiée, le déclaration return null;est implicitement ajouté au corps de la
fonction.

foo() {}

assert(foo() == null);

Operators
Dart définit les opérateurs indiqués dans le tableau suivant. Vous pouvez
remplacer plusieurs de ces opérateurs, comme décrit dans Surcharge des
opérateurs .

Description Opérateur

postfix unaire expr++ expr-- () [] . ?.

préfixe unaire -expr !expr ~expr ++expr --expr

multiplicatif * / % ~/

additif + -

décalage << >> >>>

ET binaire &

XOR binaire ^

OU binaire |

comparaison et test de type >= > <= < as is is!

égalité == !=

28
Description Opérateur

ET logique &&

OU logique ||

si null ??

conditionnel ternaire expr1 ? expr2 : expr3

cascade ..

affectation = *= /= += -= &= ^= etc.

Attention: Operator precedence is an approximation of the behavior of a Dart parser. For


definitive answers, consult the grammar in the Spécification du langage Dart.

Lorsque vous utilisez des opérateurs, vous créez des expressions. Voici
quelques exemples des expressions d'opérateur:

a++
a + b
a = b
a == b
c ? a : b
a is T

Dans la table des opérateurs , chaque opérateur a une priorité plus élevée que
les opérateurs dans les lignes qui le suivent. Par exemple, l'opérateur
multiplicatif %a une priorité plus élevée (et donc sera exécuté avant) que
l'opérateur d'égalité ==, qui lui-même a une priorité plus élevée que l'opérateur
logique AND &&. Cette la priorité signifie que les deux lignes de code suivantes
exécutent la même chose:

// Parentheses improve readability.


if ((n % i == 0) && (d % i == 0)) ...

// Harder to read, but equivalent.


if (n % i == 0 && d % i == 0) ...

Attention: Pour les opérateurs travaillant sur deux opérandes, l'opérande le


plus à gauche détermine quelle version de l'opérateur est utilisée. Par
exemple, si vous avez un objet Vector et un objet Point, aVector +
aPoint utilisera l'opérateur + de l'objet Vector.

29
Opérateurs arithmétiques
Dart supports the usual arithmetic operators, as shown in the following table.

Opérateur Description

+ Ajouter
– Soustraire

-expr Moins unaire, également connu sous le


nom de négation (inverser le signe de
l'expression)
* Multiplier

/ Diviser
~/ Diviser, renvoyer un résultat entier
% Récupère le reste d'une division entière
(modulo)

Exemple:

assert(2 + 3 == 5);
assert(2 - 3 == -1);
assert(2 * 3 == 6);
assert(5 / 2 == 2.5); // Result is a double
assert(5 ~/ 2 == 2); // Result is an int
assert(5 % 2 == 1); // Remainder

assert('5/2 = ${5 ~/ 2} r ${5 % 2}' == '5/2 = 2 r 1');

Dart prend également en charge la pré-incrémentation, la post-incrémentation,


la pré-décrémentation et la post-décrémentation.

Opérateur Description

++var var = var + 1 (au moment de


l’exécution de l'instruction,
valeur contient var + 1)

30
Opérateur Description

var++ var = var + 1 (au moment de


l’exécution de l'instruction,
valeur contient var)

--var var = var – 1 (au moment de


l’exécution de l'instruction,
valeur contient var – 1)

var-- var = var – 1 (au moment de


l’exécution de l'instruction,
valeur contient var)

Exemple:

var a, b;

a = 0;
b = ++a; // Increment a before b gets its value.
assert(a == b); // 1 == 1

a = 0;
b = a++; // Increment a AFTER b gets its value.
assert(a != b); // 1 != 0

a = 0;
b = --a; // Decrement a before b gets its value.
assert(a == b); // -1 == -1

a = 0;
b = a--; // Decrement a AFTER b gets its value.
assert(a != b); // -1 != 0

31
Égalité et opérateurs relationnels
Le tableau suivant répertorie les significations des opérateurs d'égalité et
relationnels.

Opérateur Description

== Égal; voir discussion ci-


dessous
!= Inégal
> Plus grand que

< Plus petit que


>= Plus grand ou égal à
<= Plus petit que ou égal à

Pour vérifier si deux objets x et y représentent la même chose, utilisez la


l'opérateur ==. (Dans les rares cas où vous avez besoin de savoir si deux les
objets sont exactement le même objet, utilisez la fonction identical().) Voici
comment l'opérateur == fonctionne:

1. Si x ou y est null alors renvoie true si les deux sont nuls et false si
seulement l'un est nul.
2. Renvoie le résultat de l'invocation de la méthode x.==(y). (C'est vrai, des
opérateurs tels que == sont des méthodes qui sont invoquées sur leur
première opérande. Vous pouvez même remplacer plusieurs
opérateurs, y compris ==comme vous verrez dans Surcharge des
opérateurs .)

Voici un exemple d’utilisation de l’égalité et du relationnel. les opérateurs:

assert(2 == 2);
assert(2 != 3);
assert(3 > 2);
assert(2 < 3);
assert(3 >= 3);
assert(2 <= 3);

32
Opérateurs de test de type
Les opérateurs as, is et is! sont pratiques pour vérifier les types durant
l’exécution du programme.

Opérateur Description

as Conversion de type (cast). Egalement utilisé pour spécifier les préfixes de b


is Vrai si l'objet a le type spécifié
is! Faux si l'objet a le type spécifié

Le résultat de obj is T est vrai si obj implémente l'interface spécifié par T. Par
exemple, obj is Object est toujours vrai.

Utilisez l'opérateur as pour convertir un objet d'un type vers un autre type. En
général, vous devriez l’utiliser comme raccourci d'une utilisation de
l'opérateur is suivi d'une expression utilisant cet objet. Par exemple,
considérons le code suivant:

if (emp is Person) {
// Type check
emp.firstName = 'Bob';
}

Vous pouvez raccourcir le code en utilisant l'opérateur as:

(emp as Person).firstName = 'Bob';

Remarque: Le code n’est pas équivalent. Si emp est nul ou pas une personne,
le premier exemple (avec is) ne fait rien; le seconde (avec as) lève une
exception.

Opérateurs d'assignation
Comme vous l’avez déjà vu, vous pouvez attribuer des valeurs à l’aide de
l'opérateur =. Pour n'affecter une valeur que si elle est nulle, Utilisez
l'opérateur ??=.

// Assign value to a
a = value;
// Assign value to b if b is null; otherwise, b stays the
same

33
b ??= value;

Opérateurs d'assignation composés tels que +=combiner une opération avec


une affectation.

= –= /= %= >>= ^=

+= *= ~/= <<= &= |=

Here’s how compound assignment operators work:

Opérateurs d'assignation Expression équivalente

Pour un a op= b a = a op b
opérateur op:

Exemple: a += b a = a + b

L'exemple suivant utilise l'affectation et les opérateurs d'assignation:

var a = 2; // Assign using =


a *= 3; // Assign and multiply: a = a * 3
assert(a == 6);

Opérateurs logiques
You can invert or combine boolean expressions using the logical operators.

Opérateur Description

!expr Inverse l'expression


suivante (modifie false en
true et vice versa)
|| OU logique
&& ET logique

Voici un exemple d'utilisation des opérateurs logiques:

if (!done && (col == 0 || col == 3)) {


// ...Do something...
}

34
Opérateurs binaires et de décalage
You can manipulate the individual bits of numbers in Dart. Usually, you’d use
these bitwise and shift operators with integers.

Opérateur Description

& ET
| OU
^ EOR

~expr Complément de bit unaire (les 0 deviennent les 1;


les 1 deviennent les 0)
<< Décalage de bits à gauche
>> Décalage de bits à droite

Voici un exemple d’utilisation d’opérateurs de décalage et de bits:

final value = 0x22;


final bitmask = 0x0f;

assert((value & bitmask) == 0x02); // AND


assert((value & ~bitmask) == 0x20); // AND NOT
assert((value | bitmask) == 0x2f); // OR
assert((value ^ bitmask) == 0x2d); // XOR
assert((value << 4) == 0x220); // Shift left
assert((value >> 4) == 0x02); // Shift right

Expressions conditionnelles
Dart a deux opérateurs qui vous permettent d’évaluer de manière concise des
expressions qui pourraient autrement nécessiter un instruction if-else:

condition ? expr1 : expr2

Si condition est vrai, évalue expr1 (et retourne sa valeur); sinon, évalue
et renvoie la valeur de expr2.
expr1 ?? expr2

35
Si expr1 est non-null, renvoie sa valeur; sinon, évalue et renvoie la
valeur de expr2.

Quand vous devez assigner une valeur basé sur une expression booléenne,
envisager d'utiliser l'opérateur ternaire ?:.

var visibility = isPublic ? 'public' : 'private';

Si l'expression booléenne teste la nullité, envisager d'utiliser ??.

String playerName(String name) => name ?? 'Guest';

L’exemple précédent aurait pu être écrit d’au moins deux autres manières,
mais pas aussi succinctement:

// Slightly longer version uses ?: operator.


String playerName(String name) => name != null ? name :
'Guest';

// Very long version uses if-else statement.


String playerName(String name) {
if (name != null) {
return name;
} else {
return 'Guest';
}
}

Notation en cascade (..)


La notation cascade (..) vous permet de faire une séquence d'opérations sur
le même objet. En plus des appels de fonction, vous pouvez également
accéder aux champs de ce même objet. Cela vous évite souvent de créer une
variable temporaire et vous permet d'écrire plus de code fluide.

Considérons le code suivant:

querySelector('#confirm') // Get an object.


..text = 'Confirm' // Use its members.
..classes.add('important')
..onClick.listen((e) => window.alert('Confirmed!'));

Le premier appel de méthode, querySelector(), retourne un objet sélecteur. Le


code qui suit la notation en cascade fonctionne sur cet objet sélecteur, en
ignorant les valeurs ultérieures pourrait être retourné.

36
L'exemple précédent est équivalent à:

var button = querySelector('#confirm');


button.text = 'Confirm';
button.classes.add('important');
button.onClick.listen((e) => window.alert('Confirmed!'));

Vous pouvez également imbriquer vos cascades. Par exemple:

final addressBook = (AddressBookBuilder()


..name = 'jenny'
..email = 'jenny@example.com'
..phone = (PhoneNumberBuilder()
..number = '415-555-0100'
..label = 'home')
.build())
.build();

Faites attention à construire votre cascade sur une fonction qui retourne un
objet réel. Par exemple, le code suivant échoue:

var sb = StringBuffer();
sb.write('foo')
..write('bar'); // Error: method 'write' isn't defined
for 'void'.

L'appel sb.write() retourne void, et vous ne pouvez pas construire une


cascade sur void.

Remarque: À proprement parler, la notation «double point» pour cascades


n'est pas un opérateur. Cela fait partie de la syntaxe Dart.

Other operators
Vous avez vu sans doute déjà croisé les opérateurs restants présenté ci-
dessous:

Opérateur Nom Description

() Application de Représente un appel de fonction


fonction
[] Accès à la liste Fait référence à la valeur à l'index spécifié
dans la liste

37
Opérateur Nom Description
. Accès aux membres Fait référence à une propriété d'une
expression; Exemple: foo.bar sélectionne la
propriété bar de l'expression foo
?. Accès conditionnel Comme ., mais l'opérande le plus à gauche
aux membres peut être nul; Exemple: foo?.bar sélectionne
la propriété bar de l'expression foo sauf
si foo est nul (auquel cas la valeur
de foo?.bar est nulle)

Pour plus d'informations sur les opérateurs ., ?., et .., voir Les classes .

Instructions de contrôle de flux


Vous pouvez contrôler le flux de votre code Dart en utilisant l’un des éléments
suivants:

 if et else
 for
 while et do-while
 break et continue
 switch et case
 assert

Vous pouvez également affecter le flux de contrôle en utilisant try-


catch et throw comme expliqué dans Les exceptions .

If and else
Dart supporte l'instruction if et son instruction optionnelle else, comme
l'échantillon de code suivant montre. Voir aussi Les expressions
conditionnelles .

if (isRaining()) {
you.bringRainCoat();
} else if (isSnowing()) {
you.wearJacket();
} else {
car.putTopDown();
}

38
Contrairement à JavaScript, les conditions doivent utiliser des valeurs
booléennes, rien d'autre. Voir Booleanspour plus d'informations.

For loops
Vous pouvez itérer avec la standard boucle for. Par exemple:

var message = StringBuffer('Dart is fun');


for (var i = 0; i < 5; i++) {
message.write('!');
}

Les Closures de Dart pour les boucles for capturent la valeur de l'index, et
évite ainsi un piège commun trouvé dans JavaScript. Par exemple,
considérons:

var callbacks = [];


for (var i = 0; i < 2; i++) {
callbacks.add(() => print(i));
}
callbacks.forEach((c) => c());

La sortie est 0 puis 1, comme prévu. En revanche, le même exemple en


javascript afficherai 2 puis 2 en JavaScript.

Si l’objet que vous parcourez est un Iterable, vous pouvez utiliser la


méthode forEach(). Utiliser forEach() est une bonne option si vous n’avez pas
besoin de connaître le compteur d'itération actuel:

candidates.forEach((candidate) => candidate.interview());

Les classes itérables telles que List et Set prennent également en charge la
form for-in de l'itération:

var collection = [0, 1, 2];


for (var x in collection) {
print(x); // 0 1 2
}

39
Les boucle While et do-while
Une boucle while évalue la condition avant l'itération:

while (!isDone()) {
doSomething();
}

Une boucle do-while évalue la condition après l'itération:

do {
printLine();
} while (!atEndOfPage());

Break et continue
Utilisez break pour sortie de la boucle:

while (true) {
if (shutDownRequested()) break;
processIncomingRequests();
}

Utilisez continue pour passer à la prochaine itération de la boucle:

for (int i = 0; i < candidates.length; i++) {


var candidate = candidates[i];
if (candidate.yearsExperience < 5) {
continue;
}
candidate.interview();
}

Vous pouvez écrire cet exemple différemment si vous utilisez


un Iterable comme une List ou un Set:

candidates
.where((c) => c.yearsExperience >= 5)
.forEach((c) => c.interview());

40
Switch and case
Dans Dart, switch réalise les comparaison avec des entiers, des chaînes ou
toute compilation constantes utilisant l'opérateur ==. Les objets comparés
doivent tous être des instances de la même classe (et aucun de ses sous-
types), et la classe ne doit pas avoir surchargée l'opérateur ==. Les types
énumérés fonctionne bien avec les instruction switch.

Remarque: Les instructions Switch dans Dart sont destinées à des


circonstances limitées. comme dans les interprètes ou les scanners.

Chaque code associé à une clause case se termine en règle générale par une
instruction break. Les autres moyens valables pour terminer un code associé a
une clause case et d'utiliser les instructions continue, throw ou return.

Utiliser la clause default exécute du code lorsque aucun autre clause case ne
correspond.

var command = 'OPEN';


switch (command) {
case 'CLOSED':
executeClosed();
break;
case 'PENDING':
executePending();
break;
case 'APPROVED':
executeApproved();
break;
case 'DENIED':
executeDenied();
break;
case 'OPEN':
executeOpen();
break;
default:
executeUnknown();
}

L'exemple suivant omet l'instruction break dans une clause case générant ainsi
une erreur:

var command = 'OPEN';


switch (command) {
case 'OPEN':
executeOpen();

41
// ERROR: Missing break

case 'CLOSED':
executeClosed();
break;
}

Cependant, Dart ne supporte pas les clause case vide, permettant d’enchaîner
avec le code de la clause suivante:

var command = 'CLOSED';


switch (command) {
case 'CLOSED': // Empty case falls through.
case 'NOW_CLOSED':
// Runs for both CLOSED and NOW_CLOSED.
executeNowClosed();
break;
}

Si vous voulez vraiment utiliser ce système, vous pouvez utiliser une


instruction continue et un label de clause:

var command = 'CLOSED';


switch (command) {
case 'CLOSED':
executeClosed();
continue nowClosed;
// Continues executing at the nowClosed label.

nowClosed:
case 'NOW_CLOSED':
// Runs for both CLOSED and NOW_CLOSED.
executeNowClosed();
break;
}

Une clause case peut avoir des variables locales visibles uniquement à
l'intérieur la portée de cette clause.

42
Assert
During development, use an assert statement —
assert(condition, optionalMessage); — to disrupt normal execution if a boolean
condition is false. You can find examples of assert statements throughout this
tour. Here are some more:

// Make sure the variable has a non-null value.


assert(text != null);

// Make sure the value is less than 100.


assert(number < 100);

// Make sure this is an https URL.


assert(urlString.startsWith('https'));

To attach a message to an assertion, add a string as the second argument


to assert.

assert(urlString.startsWith('https'),
'URL ($urlString) should start with "https".');

Le premier argument de assertpeut être n'importe quelle expression qui


retourne une valeur booléenne. Si la valeur de l'expression est vrai, l'assertion
réussit et l'exécution continue. Si elle est fausse, l’assertion échoue et une
exception (une AssertionError) est levée.

When exactly do assertions work? That depends on the tools and framework
you’re using:

 Flutter enables assertions in mode debug.


 Development-only tools such as dartdevc typically enable assertions by
default.
 Some tools, such as dart et dart2js, support assertions through a
command-line flag: --enable-asserts.

In production code, assertions are ignored, and the arguments to assert aren’t
evaluated.

43
Exceptions
Your Dart code can throw and catch exceptions. Exceptions are errors
indicating that something unexpected happened. If the exception isn’t caught,
the isolate that raised the exception is suspended, and typically the isolate and
its program are terminated.

Contrairement à Java, toutes les exceptions de Dart sont des exceptions non
contrôlées. Les méthodes ne déclarent pas quelles exceptions elles pourraient
générer, et vous êtes pas nécessaire pour attraper des exceptions.

Dart fournit les types Exception et Error, ainsi que de nombreux sous-types
prédéfinis. Vous pouvez bien sûr définir vos propres exceptions. Cependant,
les programmes Dart peuvent jeter tout objet non null - pas seulement les
objets Exception et Error - en tant qu'exception.

Throw
Voici un exemple de lancer, ou raising, une exception:

throw FormatException('Expected at least 1 section');

Vous pouvez également lancer des objets arbitraires:

throw 'Out of llamas!';

Remarque: Le code de qualité de production renvoie généralement les types


qui implémentent Error ou Exception.

Because throwing an exception is an expression, you can throw exceptions in


=> statements, as well as anywhere else that allows expressions:

void distanceTo(Point other) => throw


UnimplementedError();

Catch
La capture d’une exception stoppe la propagation (à moins que vous ne
renvoyiez l'exception). Détecter une exception vous donne une chance de la
gérer:

44
try {
breedMoreLlamas();
} on OutOfLlamasException {
buyMoreLlamas();
}

Pour gérer un code pouvant générer plusieurs types d’exception, vous pouvez:
spécifier plusieurs clauses de capture. La première clause de capture qui
correspond au motif de l'exception sera exécuté. Si la clause capturé ne
spécifiez pas de type, cette clause peut gérer n'importe quel type de motif
d'exception:

try {
breedMoreLlamas();
} on OutOfLlamasException {
// A specific exception
buyMoreLlamas();
} on Exception catch (e) {
// Anything else that is an exception
print('Unknown exception: $e');
} catch (e) {
// No specified type, handles all
print('Something really unknown: $e');
}

Comme le montre le code précédent, vous pouvez utiliser soit on ou catch ou


les deux. Utilisez on lorsque vous devez spécifier le type d'exception.
Utilisez catch quand votre gestionnaire d'exceptions a besoin en plus de l'objet
qui a produit l'exception.

Vous pouvez spécifier un ou deux paramètres à catch(). Le premier est


l'exception qui a été lancée, et le second est la trace de la pile (un
objet StackTrace).

try {
// ···
} on Exception catch (e) {
print('Exception details:\n $e');
} catch (e, s) {
print('Exception details:\n $e');
print('Stack trace:\n $s');
}

Pour gérer partiellement une exception, tout en lui permettant de se propager,


Utilisez le mot clé rethrow.

void misbehave() {

45
try {
dynamic foo = true;
print(foo++); // Runtime error
} catch (e) {
print('misbehave() partially handled
${e.runtimeType}.');
rethrow; // Allow callers to see the exception.
}
}

void main() {
try {
misbehave();
} catch (e) {
print('main() finished handling ${e.runtimeType}.');
}
}

Finally
Pour vous assurer que du code est exécuté, qu’une exception soit levée ou
non, utilisez une clause finally. Sinon catch ne correspond à l'exception, la
clause finally sera exécutée. Notez que la clause finally sera exécutée même
si une clause de capture à été exécutée.

try {
breedMoreLlamas();
} finally {
// Always clean up, even if an exception is thrown.
cleanLlamaStalls();
}

La clause finally s'exécute après toute correspondance de clausecatch:

try {
breedMoreLlamas();
} catch (e) {
print('Error: $e'); // Handle the exception first.
} finally {
cleanLlamaStalls(); // Then clean up.
}

En savoir plus en lisant le Exceptions section de la visite de la bibliothèque.

46
Classes
Dart est un langage orienté objet avec classes et héritage mixin-based.
Chaque objet est une instance d'une classe et toutes les classes descende
de Object. L'héritage mixin-based signifie que même si chaque classe (à
l'exception de Object) a exactement une seule super classe, un corps de
classe peut être réutilisé dans plusieurs hiérarchies de classes.

Utilisation des membres de la classe


Les objets ont des membersconstitué de fonctions et de données
( méthodes and variables d'instance , respectivement). Lorsque vous appelez
une méthode, vous l'invoquez sur un objet: la méthode a accès aux fonctions
de cet objet et à ses données.

Utilisez un point (.) pour faire référence à une variable d’instance ou à une
méthode:

var p = Point(2, 2);

// Set the value of the instance variable y.


p.y = 3;

// Get the value of y.


assert(p.y == 3);

// Invoke distanceTo() on p.
num distance = p.distanceTo(Point(4, 4));

Utilisez ?. au lieu de . pour éviter une exception quand l'objet est nul:

// If p is non-null, set its y value to 4.


p?.y = 4;

Utiliser des constructeurs


Vous pouvez créer un objet en utilisant un constructeur . Les noms de
constructeur peuvent être soit ClassName ou ClassName.identifier. Par exemple, le
code suivant crée des objets Point en utilisant les
constructeurs Point() et Point.fromJson():

var p1 = Point(2, 2);


var p2 = Point.fromJson({'x': 1, 'y': 2});

47
Le code suivant a le même effet, mais utilise le mot clé new avant le nom du
constructeur:

var p1 = new Point(2, 2);


var p2 = new Point.fromJson({'x': 1, 'y': 2});

Version note:Le mot clé new est devenu optionnel en Dart 2.

Certaines classes fournissent des constructeurs constants . Pour créer une


constante de compilation à l'aide d'un constructeur de constante, mettre le mot
clé const avant le nom du constructeur:

var p = const ImmutablePoint(2, 2);

La construction de deux constantes de compilation identiques donne une


seule, instance canonique:

var a = const ImmutablePoint(1, 1);


var b = const ImmutablePoint(1, 1);

assert(identical(a, b)); // They are the same instance!

Dans un contexte constant , vous pouvez omettre le const devant un


constructeur ou littéral. Par exemple, regardez ce code, qui crée une carte
const:

// Lots of const keywords here.


const pointAndLine = const {
'point': const [const ImmutablePoint(0, 0)],
'line': const [const ImmutablePoint(1, 10), const
ImmutablePoint(-2, 11)],
};

Vous pouvez omettre tout sauf la première utilisation du const mot-clé:

// Only one const, which establishes the constant context.


const pointAndLine = {
'point': [ImmutablePoint(0, 0)],
'line': [ImmutablePoint(1, 10), ImmutablePoint(-2, 11)],
};

Si un constructeur constant est en dehors d'un contexte constant et est


invoqué sans const, cela crée un objet non constant :

var a = const ImmutablePoint(1, 1); // Creates a constant


var b = ImmutablePoint(1, 1); // Does NOT create a
constant

48
assert(!identical(a, b)); // NOT the same instance!

Note de version: Le mot clé const est devenu facultatif dans un contexte constant dans Dart
2.

Obtenir le type d'un objet


Pour obtenir le type d’objet au moment de l’exécution, vous pouvez utiliser la
propriété runtimeType de Object qui retourne un objet de type Type.

print('The type of a is ${a.runtimeType}');

Jusqu’ici, vous avez vu comment utiliser les classes. Le reste de cette section
montre comment implémenter des classes

Variables d'instance
Voici comment vous déclarez des variables d'instance:

class Point {
num x; // Declare instance variable x, initially null.
num y; // Declare y, initially null.
num z = 0; // Declare z, initially 0.
}

Toutes les variables d'instance non initialisées ont la valeur null.

Toutes les variables d'instance génèrent une méthode getter implicite. Les
variables d'instance non finale génèrent également une méthode setter. Pour
plus de détails, voir Getters et setters .

class Point {
num x;
num y;
}

void main() {
var point = Point();
point.x = 4; // Use the setter method for x.
assert(point.x == 4); // Use the getter method for x.
assert(point.y == null); // Values default to null.
}

49
Si vous initialisez une variable d’instance là où elle est déclarée (au lieu de
l'initialiser via un constructeur ou une méthode), la valeur est définie lorsque
l’instance est créé avant même l'appel du constructeur qui peut donc utiliser
cette variable d'instance.

Constructors
Déclarez un constructeur en créant une fonction portant le même nom que son
classe (plus, éventuellement, un identifiant supplémentaire comme décrit
dans Constructeurs nommés ). La forme la plus courante de constructeur, le
constructeur génératif, crée une nouvelle instance d'une classe:

class Point {
num x, y;

Point(num x, num y) {
// There's a better way to do this, stay tuned.
this.x = x;
this.y = y;
}
}

Les mot clé this fait référence à l'instance actuelle.

Remarque: Utilisez this uniquement en cas de conflit de noms. Sinon, le style


Dart recommande d'omettre this.

Il est tellement courant qu'un constructeur se limite à initialiser des variable


d'instance que Dart dispose d'une version simplifiée pour réaliser ce type de
constructeurs:

class Point {
num x, y;

// Syntactic sugar for setting x and y


// before the constructor body runs.
Point(this.x, this.y);
}

Constructeurs par défaut


Si vous ne déclarez pas de constructeur, un constructeur par défaut est fourni.
pour vous. Le constructeur par défaut n'a pas d'argument et appelle le
constructeur sans argument de la superclasse.

50
Les constructeurs ne sont pas hérités
Les classes filles n’héritent pas des constructeurs de leur superclasse. Une
classe fille qui ne déclare aucun constructeur n’a que le constructeur par
défaut (aucun argument, aucun nom).

Constructeurs nommés
Utiliser un constructeur nommé pour implémenter plusieurs constructeurs pour
une classe ou pour plus de clarté:

class Point {
num x, y;

Point(this.x, this.y);

// Named constructor
Point.origin() {
x = 0;
y = 0;
}
}

Rappelez-vous que les constructeurs ne sont pas hérités, ce qui signifie qu'un
le constructeur nommé de la superclasse n’est pas hérité par une classe fille.
Si vous voulez que la classe fille soit créée avec un constructeur nommé défini
dans sa superclasse, vous devez implémenter à nouveau ce constructeur
dans la classe fille.

Appeler un constructeur de superclasse


Par défaut, un constructeur (nommé ou non) d’une classe fille appelle le
constructeur par défaut de la superclasse. Le constructeur de la superclasse
s’exécute avant le constructeur de la classe fille. Si l’implémentation du
constructeur utilise l'initialisation par liste, cette initialisation s’exécute avant
l’appel de la superclasse. En résumé, l'ordre d'exécution est le suivant:

1. l'initialisation par liste


2. constructeur par défaut de la superclasse
3. constructeur par défaut de la classe fille

Si la superclasse n’a pas de constructeur non nommé, sans argument, alors


vous devez appeler manuellement l'un des constructeurs du superclasse.
Spécifiez le constructeur de la superclasse après un deux-points ( :), juste
avant le corps du constructeur (si le constructeur à un corps)

51
Dans l'exemple suivant, le constructeur de la classe Employee appelle le

constructeur nommé pour sa superclasse Person. Cliquez sur le bouton


pour exécuter le code.

Parce que les arguments du constructeur de la superclasse sont évalués


avant d'invoquer le constructeur, un argument peut être un appel de fonction:

class Employee extends Person {


Employee() : super.fromJson(getDefaultData());
// ···
}

Attention: Les arguments du constructeur de la superclasse n’ont pas accès


à this. Les arguments peuvent appeler des méthodes statiques, mais pas les
méthodes d'instance. car l'instance de la classe n'est pas encore créée à ce
moment.

Initialisation par liste


En plus d’appeler un constructeur de superclasse, vous pouvez également
initialiser des variables d'instance avant que le corps du constructeur
s'exécute. Séparez les instruction d'initialisation par des virgules.

// Initializer list sets instance variables before


// the constructor body runs.
Point.fromJson(Map<String, num> json)
: x = json['x'],
y = json['y'] {
print('In Point.fromJson(): ($x, $y)');
}

Warning:Le côté droit d'un initialiseur n'a pas accès à this.

Pendant le développement, vous pouvez valider les entrées en


utilisant assert dans la liste des initialisations

Point.withAssert(this.x, this.y) : assert(x >= 0) {


print('In Point.withAssert(): ($x, $y)');
}

L'initialisation par liste est pratique lorsqu'on veut définir des variables
d'instance finale. L'exemple suivant initialise 3 variables d'instance finales.

Cliquez sur le bouton pour exécuter le code.

52
Redirection de constructeurs
Parfois, le seul but d’un constructeur est de rediriger vers un autre
constructeur dans la même classe. Le corps du constructeur qui redirige est
alors vide, l’appel du constructeur apparaissant après un signe deux-points (:).

class Point {
num x, y;

// The main constructor for this class.


Point(this.x, this.y);

// Delegates to the main constructor.


Point.alongXAxis(num x) : this(x, 0);
}

Constant constructors
Si votre classe produit des objets qui ne changent jamais, vous pouvez rendre
ces objets constants. Pour ce faire, définissez un constructeur const et
assurez-vous que toutes les variables d'instance sont final.

class ImmutablePoint {
static final ImmutablePoint origin =
const ImmutablePoint(0, 0);

final num x, y;

const ImmutablePoint(this.x, this.y);


}

Les constructeurs const ne créent pas toujours de constantes. Pour plus de


détails, voir la section sur utiliser des constructeurs .

Constructeurs de type fabrique


Utilisez le mot clé factory lors de l'implémentation d'un constructeur qui ne
crée pas toujours une nouvelle instance de sa classe. Par exemple, un
constructeur de type fabrique peut renvoyer une instance à partir d’un cache,
ou peut renvoyer une instance d'un sous-type.

L'exemple suivant montre un constructeur de type fabrique renvoyant des


objets provenant d'un cache:

class Logger {
final String name;
53
bool mute = false;

// _cache is library-private, thanks to


// the _ in front of its name.
static final Map<String, Logger> _cache =
<String, Logger>{};

factory Logger(String name) {


if (_cache.containsKey(name)) {
return _cache[name];
} else {
final logger = Logger._internal(name);
_cache[name] = logger;
return logger;
}
}

Logger._internal(this.name);

void log(String msg) {


if (!mute) print(msg);
}
}

Remarque: Les constructeurs de type fabrique n’ont pas accès à this.

Appelez un constructeur de type fabrique comme n'importe quel autre


constructeur:

var logger = Logger('UI');


logger.log('Button clicked');

Methods
Les méthodes sont des fonctions associées à une classe ou a une instance de
la classe.

Méthodes d'instance
Les méthodes d'instance sur les objets peuvent accéder aux variables
d'instance et this. La méthode distanceTo() dans l'exemple suivant est un
exemple de méthode d'instance:

import 'dart:math';

class Point {

54
num x, y;

Point(this.x, this.y);

num distanceTo(Point other) {


var dx = x - other.x;
var dy = y - other.y;
return sqrt(dx * dx + dy * dy);
}
}

Getters et setters
Les getters et les setters sont des méthodes spéciales qui permettent de lire et
d’écrire les propriétés d’un objet. Rappelons que chaque variable d'instance a
un getter implicite, plus un setter si besoin. Vous pouvez créer des propriétés
supplémentaires en implémentant des getters et des setters, en utilisant les
mots clés get et set.

class Rectangle {
num left, top, width, height;

Rectangle(this.left, this.top, this.width, this.height);

// Define two calculated properties: right and bottom.


num get right => left + width;
set right(num value) => left = value - width;
num get bottom => top + height;
set bottom(num value) => top = value - height;
}

void main() {
var rect = Rectangle(3, 4, 20, 15);
assert(rect.left == 3);
rect.right = 12;
assert(rect.left == -8);
}

Avec les getters et les setters, vous pouvez commencer par utiliser les
variables d'instance, puis plus tard y accéder en définissant des méthodes, le
tout sans changer le code client.

Remarque: Les opérateurs tels que incrément (++) fonctionnent de la manière


attendue, qu'un getter soit explicitement défini ou non. Pour éviter effet
inattendu, l'opérateur appelle le getter exactement une fois, en enregistrant sa
valeur dans une variable temporaire.

55
Méthodes abstraites
Les méthodes d’instance, les getter et setter peuvent être abstraites. Elles
sont déclarées mais leur implémentation est laissée à la charge des classes
qui hérite de leur classe. Les méthodes abstraites ne peuvent exister que dans
des classes abstraites .

Pour rendre une méthode abstraite, utilisez un point-virgule (;) au lieu d'un
corps de méthode ({}):

abstract class Doer {


// Define instance variables and methods...

void doSomething(); // Define an abstract method.


}

class EffectiveDoer extends Doer {


void doSomething() {
// Provide an implementation, so the method is not
abstract here...
}
}

Classes abstraites
Utilisez le mot clé abstract pour définir un abstract class - Une classe qui ne
peut pas être instancié. Les classes abstraites sont utiles pour définir
interfaces, souvent avec une certaine implémentation. Si vous voulez que la
classe abstraite semble instanciable, définissez un constructeur de fabrique.

Les classes abstraites ont souvent méthodes abstraites . Voici un exemple de


déclaration d’une classe abstraite qui a une méthode abtraite:

// This class is declared abstract and thus


// can't be instantiated.
abstract class AbstractContainer {
// Define constructors, fields, methods...

void updateChildren(); // Abstract method.


}

Interfaces implicites
Chaque classe définit implicitement une interface contenant toute les variables
d'instance. et toutes les interfaces implémentées. Si vous voulez créer une

56
classe A qui supporte l’API de la classe B sans hériter de l'implémentation de
B, la classe A doit implémenter l’interface B.

Une classe implémente une ou plusieurs interfaces en les déclarant dans une
clause implements, puis en fournissant les API requises par l'interfaces. Par
exemple:

// A person. The implicit interface contains greet().


class Person {
// In the interface, but visible only in this library.
final _name;

// Not in the interface, since this is a constructor.


Person(this._name);

// In the interface.
String greet(String who) => 'Hello, $who. I am $_name.';
}

// An implementation of the Person interface.


class Impostor implements Person {
get _name => '';

String greet(String who) => 'Hi $who. Do you know who I


am?';
}

String greetBob(Person person) => person.greet('Bob');

void main() {
print(greetBob(Person('Kathy')));
print(greetBob(Impostor()));
}

Voici un exemple de spécification qu'une classe implémente plusieurs


interfaces:

class Point implements Comparable, Location {...}

Héritage de classe
Utilisez extends pour créer une sous-classe, et super pour faire référence à la
superclasse:

class Television {
void turnOn() {
_illuminateDisplay();
57
_activateIrSensor();
}
// ···
}

class SmartTelevision extends Television {


void turnOn() {
super.turnOn();
_bootNetworkInterface();
_initializeMemory();
_upgradeApps();
}
// ···
}

Surcharger des membres


Les classes filles peuvent remplacer les méthodes d'instance, les getters et les
setters de la super classe. Vous pouvez utiliser le mot clé @override pour
indiquer que vous annulez et surchargez intentionnellement un
membre (généralement une méthode):

class SmartTelevision extends Television {


@override
void turnOn() {...}
// ···
}

Pour être certains que restreindre le type d’un paramètre de méthode ou d’une
variable d’instance dans le code est type safe, vous pouvez utiliser le mot
clé covariant.

Surcharge des opérateurs


Vous pouvez surcharger les opérateurs indiqués dans le tableau suivant. Par
exemple, si vous définissez une classe Vector, vous pouvez définir une
méthode + pour réaliser l'addition de 2 vecteurs.

< + | []

> / ^ []=

<= ~/ & ~

>= * << ==

58
– % >>

Remarque: Vous avez peut-être remarqué que !=n'est pas un opérateur que
l'on peut surcharger. L'expression e1 != e2est juste un raccourci syntaxique
pour !(e1 == e2).

Voici un exemple de classe qui remplace les opérateurs + et -:

class Vector {
final int x, y;

Vector(this.x, this.y);

Vector operator +(Vector v) => Vector(x + v.x, y + v.y);


Vector operator -(Vector v) => Vector(x - v.x, y - v.y);

// Operator == and hashCode not shown. For details, see


note below.
// ···
}

void main() {
final v = Vector(2, 3);
final w = Vector(2, 2);

assert(v + w == Vector(4, 5));


assert(v - w == Vector(0, 1));
}

Si vous surchargez ==, vous devez également surcharger le getter hashCode.


Pour un exemple de surcharge de == et hashCode, voir Implémentation des
tableaux associatifs.

Pour plus d'informations sur la surcharge en général, voir Héritage de classe .

noSuchMethod()
Détecter ou réagir lorsque le code tente d’utiliser une méthode non existante
ou variable d'instance non définie, vous pouvez surcharger noSuchMethod():

class A {
// Unless you override noSuchMethod, using a
// non-existent member results in a NoSuchMethodError.
@override
void noSuchMethod(Invocation invocation) {

59
print('You tried to use a non-existent member: ' +
'${invocation.memberName}');
}
}

Vous ne peut pas invoquer une méthode non implémentée à moins


qu'une des affirmations suivantes soit vrai:

 Le récepteur a le type statique dynamic.


 Le récepteur a un type statique qui définit la méthode non implémentée
(le résumé est OK), et le type dynamique du récepteur a une
implémentation de noSuchMethod()qui est différente de celui de la
classe Object.

Pour plus d'informations, voir le document informel spécification de transfert


noSuchMethod.

Les types énumérés


Types énumérés, souvent appelés enumerations ou enums, sont un type
particulier de classe utilisé pour représenter un nombre fixe de valeurs
constantes.

Utilisation d'enums
Déclarer un type énuméré en utilisant le mot clé enum:

enum Color { red, green, blue }

Chaque valeur dans une énumération a un index, qui retourne la position de


base zéro de la valeur dans la déclaration enum. Par exemple, la première
valeur a l'indice 0, et la deuxième valeur a l'indice 1.

assert(Color.red.index == 0);
assert(Color.green.index == 1);
assert(Color.blue.index == 2);

Pour obtenir une liste de toutes les valeurs de l'énumération, utiliser la


contant values des enums

List<Color> colors = Color.values;


assert(colors[2] == Color.blue);

Vous pouvez utiliser des enums dans instructions switch , et vous recevrez un
avertissement si vous ne gérez pas toutes les valeurs de l’enum:

60
var aColor = Color.blue;

switch (aColor) {
case Color.red:
print('Red as roses!');
break;
case Color.green:
print('Green as grass!');
break;
default: // Without this, you see a WARNING.
print(aColor); // 'Color.blue'
}

Les types énumérés ont les limites suivantes:

 Vous ne pouvez pas sous-classer, mixer ou implémenter une


énumération.
 Vous ne pouvez pas explicitement instancier une énumération.

For more information, see the Spécification du langage Dart.

Ajout de fonctionnalités à une classe:


mixins
Les mixins sont un moyen d'utiliser le code d'une classe dans de multiple
hiérarchies de classes.

Pour utiliser un mixin. Utilisez le mot clé with suivi d'un ou plusieurs noms de
mixin. L'exemple suivant montre deux classes qui utilisent mixins:

class Musician extends Performer with Musical {


// ···
}

class Maestro extends Person


with Musical, Aggressive, Demented {
Maestro(String maestroName) {
name = maestroName;
canConduct = true;
}
}

Pour implémenter un mixin, créez une classe qui étend Object et ne déclare
aucun constructeur. A moins que vous ne vouliez que votre mixin soit utilisable

61
comme classe ordinaire, Utilisez le mot clé mixin au lieu de class. Par
exemple:

mixin Musical {
bool canPlayPiano = false;
bool canCompose = false;
bool canConduct = false;

void entertainMe() {
if (canPlayPiano) {
print('Playing piano');
} else if (canConduct) {
print('Waving hands');
} else {
print('Humming to self');
}
}
}

Pour spécifier que seuls certains types peuvent utiliser le mixin - par exemple,
afin que votre mixin puisse invoquer une méthode qu’elle ne définit pas -
utilisez onpour spécifier la superclasse requise:

mixin MusicalPerformer on Musician {


// ···
}

Version note:Le support du mot clé mixin a été introduit dans Dart 2.1. Les versions
précédentes utilisent abstract class à la place. Pour plus d’informations sur les
modifications de mixin 2.1, voir la Dart SDK changelog et spécification de mixin 2.1.

Variables et méthodes de classe


Utilisez le mot clé static pour implémenter des variables et des méthodes à
l'échelle de la classe C'est à dire qu'il n'existe qu'une seule instance de la
méthode ou de la méthode pour toutes les instances de la classe.

Variables statiques
Les variables statiques (variables de classe) sont utiles pour les états et les
classes constantes:

class Queue {
static const initialCapacity = 16;
// ···
}
62
void main() {
assert(Queue.initialCapacity == 16);
}

Les variables statiques ne sont pas initialisées avant leur utilisation.

Remarque: Cette page suit la recommandation de style et préfère utiliser la


notation lowerCamelCase pour les noms constants.

Méthodes statiques
Les méthodes statiques (méthodes de classe) ne fonctionnent pas sur une
instance particulière, et donc n'ont pas accès à this. Par exemple:

import 'dart:math';

class Point {
num x, y;
Point(this.x, this.y);

static num distanceBetween(Point a, Point b) {


var dx = a.x - b.x;
var dy = a.y - b.y;
return sqrt(dx * dx + dy * dy);
}
}

void main() {
var a = Point(2, 2);
var b = Point(4, 4);
var distance = Point.distanceBetween(a, b);
assert(2.8 < distance && distance < 2.9);
print(distance);
}

Remarque: Utiliser plutôt des fonctions globales, au lieu de méthodes


statiques, pour réaliser des actions générale non relative à une classe en
particulier.

Vous pouvez utiliser des méthodes statiques comme constantes de


compilation. Par exemple, vous pouvez transmettre une méthode statique en
tant que paramètre à un constructeur constant.

63
Generics
Si vous consultez la documentation de l'API concernant les tableaux simples
et donc le type List, vous verrez que le le type est en fait List<E>. La notation
<...> indique que la List est générique (ou utilise un type paramétrée) type—a
type that has formal type parameters. By convention, most type variables have
single-letter names, such as E, T, S, K, and V.

Pourquoi utiliser des génériques?


Les génériques sont souvent nécessaires pour sécuriser le type, mais ils
induisent d'autres avantages:

 Si vous spécifiez correctement les types génériques, le code généré est


meilleur.
 Vous pouvez utiliser des génériques pour réduire la duplication de code.

Si vous souhaitez qu'une liste ne contienne que des chaînes, vous pouvez le
déclarer comme List<String>(lisez cela comme "liste de chaîne"). De cette
façon vous, vos collègues programmeurs et vos outils peuvent détecter que
l’attribution d’autre chose qu'une chaîne à la liste est probablement une erreur.
Voici un exemple:

var names = List<String>();


names.addAll(['Seth', 'Kathy', 'Lars']);
names.add(42); // Error

Une autre raison d'utiliser des génériques est de réduire la duplication de


code. Les génériques vous permettent de partager une interface et une
implémentation uniques entre de nombreux types, tout en tirant parti des
avantages statiques une analyse. Par exemple, supposons que vous créez
une interface pour mettre en cache un objet:

abstract class ObjectCache {


Object getByKey(String key);
void setByKey(String key, Object value);
}

Vous découvrez que vous voulez une version spécifique pour les chaînes de
caractère de cette interface, alors vous créez une autre interface:

abstract class StringCache {


String getByKey(String key);
void setByKey(String key, String value);

64
}

Plus tard, vous décidez que vous voulez une version spécifique de l'interface
pour les entiers… Vous commencer où nous voulons en venir ?

Les types génériques peuvent vous éviter de créer toutes ces interfaces. Au
lieu de cela, vous pouvez créer une interface unique prenant un paramètre de
type:

abstract class Cache<T> {


T getByKey(String key);
void setByKey(String key, T value);
}

Dans ce code, T est le type de remplaçant. C’est un espace réservé que vous
pouvez penser à un type qu'un développeur définira plus tard.

Utiliser une collection de littéraux


List, set, and map literals can be parameterized. Parameterized literals are just
like the literals you’ve already seen, except that you add<type> (for lists and
sets) or <keyType, valueType>(pour les tableaux associatifs) avant la parenthèse
ouvrante. Voici un exemple d'utilisation de littéraux typés:

var names = <String>['Seth', 'Kathy', 'Lars'];


var uniqueNames = <String>{'Seth', 'Kathy', 'Lars'};
var pages = <String, String>{
'index.html': 'Homepage',
'robots.txt': 'Hints for web robots',
'humans.txt': 'We are people, not machines'
};

Utiliser des types paramétrés avec les


constructeurs
Pour spécifier un ou plusieurs types lors de l'utilisation d'un constructeur,
placez les types entre les caractères inférieurs et supérieur ( <...>) juste après
le nom de la classe. Par exemple:

var nameSet = Set<String>.from(names);

Le code suivant crée une carte qui a des clés entières et des valeurs de type
Vue:

var views = Map<int, View>();


65
Collections génériques et types
qu'elles contiennent
Dart generic types are reified, which means that they carry their type
information around at runtime. For example, you can test the type of a
collection:

var names = List<String>();


names.addAll(['Seth', 'Kathy', 'Lars']);
print(names is List<String>); // true

Remarque: In contrast, generics in Java use erasure, which means that


generic type parameters are removed at runtime. In Java, you can test
whether an object is a List, but you can’t test whether it’s a List<String>.

Restreindre le type paramétré


Lors de la mise en œuvre d'un type générique, vous voudrez peut-être limiter
les types de ses paramètres. Vous pouvez le faire en utilisant extends.

class Foo<T extends SomeBaseClass> {


// Implementation goes here...
String toString() => "Instance of 'Foo<$T>'";
}

class Extender extends SomeBaseClass {...}

C’est bien d’utiliser SomeBaseClass ou l'une de ses classes filles en tant


qu'argument générique:

var someBaseClassFoo = Foo<SomeBaseClass>();


var extenderFoo = Foo<Extender>();

Il est également possible de ne spécifier aucun argument générique:

var foo = Foo();


print(foo); // Instance of 'Foo<SomeBaseClass>'

Spécifier un type que ne soit base sur SomeBaseClass génère une erreur.

var foo = Foo<Object>();

Utiliser des méthodes génériques


66
Initialement, le support générique de Dart était limité aux classes. Une syntaxe
plus récente, appelée méthodes génériques , autorise les arguments de type
sur les méthodes et les fonctions:

T first<T>(List<T> ts) {
// Do some initial work or error checking, then...
T tmp = ts[0];
// Do some additional checking or processing...
return tmp;
}

Ici, le paramètre de type générique sur first (<T>) vous permet d'utiliser
l'argument de type T à plusieurs endroits:

 Dans le type de retour de la fonction ( T).


 Dans le type de l'argument ( List<T>).
 Dans le type d'une variable locale ( T tmp).

Pour plus d'informations sur les génériques, voir Utiliser des méthodes
génériques.

Bibliothèques et visibilité
Les directives import et library peuvent vous aider à créer un code modulaire
et partageable. Les bibliothèques fournissent non seulement des API, mais
sont une unités de confidentialité: les identifiants commençant par un trait de
soulignement (_) sont visibles uniquement à l'intérieur de la
bibliothèque. Chaque application Dart est une bibliothèque même s'il n'utilise
pas de directive library.

Libraries can be distributed using packages.

Using libraries
Utiliser importpour spécifier comment un espace de noms d'une bibliothèque
est utilisé dans une autre bibliothèque.

Par exemple, les applications Web Dart utilisent généralement la


librairie dart:html, qu'ils peuvent importer comme ceci:

import 'dart:html';

Le seul argument requis pour import est une URI spécifiant la bibliothèque.
Pour les bibliothèques intégrées, l’URI commence par le schéma dart:. Pour

67
les autres bibliothèques, vous pouvez utiliser le chemin de la librairie ou
utiliser le schéma du package:. Le schéma du package: spécifie les
bibliothèques fournies par un paquet gestionnaire tel que l'outil "pub". Par
exemple:

import 'package:test/test.dart';

Remarque: URI représente l'identificateur de ressource


uniforme. URLs(uniform resource locators) sont un type commun d’URI.

Spécifier un préfixe de bibliothèque


Si vous importez deux bibliothèques ayant des identifiants en conflit, alors
vous pouvez spécifier un préfixe pour une bibliothèque ou les deux. Par
exemple, si library1 et library2 ont tous deux une classe Element, alors vous
pourriez avoir un code comme celui qui suit:

import 'package:lib1/lib1.dart';
import 'package:lib2/lib2.dart' as lib2;

// Uses Element from lib1.


Element element1 = Element();

// Uses Element from lib2.


lib2.Element element2 = lib2.Element();

Importer seulement une partie d'une


bibliothèque
Si vous ne souhaitez utiliser qu'une partie d'une bibliothèque, vous pouvez
importer sélectivement la bibliothèque. Par exemple:

// Import only foo.


import 'package:lib1/lib1.dart' show foo;

// Import all names EXCEPT foo.


import 'package:lib2/lib2.dart' hide foo;

Chargement progressif d'une bibliothèque


Chargement différé (aussi appelé lazy loading) allows a web app to load a
library on demand, if and when the library is needed. Here are some cases
when you might use deferred loading:

 To reduce a web app’s initial startup time.

68
 Pour effectuer des tests A / B, essayez implémentations alternatives
d'un algorithme, par exemple.
 Pour charger des fonctionnalités rarement utilisées, telles que des
écrans et des boîtes de dialogue en option.

Only dart2js supports deferred loading. Flutter, the Dart VM, and dartdevc don’t support
deferred loading. For more information, see issue #33118 and issue #27776.

Pour charger progressivement une bibliothèque, vous devez d'abord l'importer


en utilisant deferred as.

import 'package:greetings/hello.dart' deferred as hello;

Lorsque vous avez besoin de la bibliothèque, appelez loadLibrary()en utilisant


l'identifiant de la bibliothèque.

Future greet() async {


await hello.loadLibrary();
hello.printGreeting();
}

Dans le code précédent, le mot clé await suspend l'exécution jusqu'à ce que la
bibliothèque soit chargée. Pour plus d'informations sur async et await,
voir support asynchrone .

Vous pouvez invoquer loadLibrary()plusieurs fois sur une bibliothèque sans


problèmes. La bibliothèque est chargée une seule fois.

Tenez compte des points suivants lorsque vous utilisez le chargement différé:

 Les constantes d’une bibliothèque différée ne sont pas des constantes


dans le fichier importé. N'oubliez pas que ces constantes n'existent pas
tant que la bibliothèque différée n'est pas chargée.
 Vous ne pouvez pas utiliser les types d'une bibliothèque différée dans le
fichier d'importation. Envisagez plutôt de déplacer les types d’interface
vers une bibliothèque importée par à la fois la bibliothèque différée et le
fichier d'importation.
 Dart insère implicitement loadLibrary()dans l'espace de noms que vous
définissez en utilisant deferred as namespaceLa
fonction loadLibrary() retourne un Future.

Implémentation de librairies
Voir Créer des packages de bibliothèque pour obtenir des conseils sur la
manière de mettre en œuvre un package de bibliothèque, notamment:

69
 Comment organiser le code source de la bibliothèque.
 Comment utiliser la directive export
 Quand utiliser la directive part
 Quand utiliser la directive library

Asynchronisme
Les bibliothèques Dart regorgent de fonctions qui retournent des
objets Future ou Stream. Ces fonctions sont asynchrones : ils reviennent
après l'installation une opération qui peut prendre beaucoup de temps (comme
I / O), sans attendre que cette opération soit terminée.

les mots clés async and await prennent en charge la programmation


asynchrone, vous permettant d'écrire du code asynchrone qui ressemble à du
code synchrone.

Gestion des Futures


Lorsque vous avez besoin du résultat qui se sera terminé que dans le future,
vous avez deux options:

 Utilisez async and await.


 Utilisez l'API Future, comme décrit dans la visite de la bibliothèque .

Le code qui utilise async and awaitest asynchrone, mais cela ressemble
beaucoup à du code synchrone. Par exemple, voici du code qui
utilise await pour attendre le résultat d'une fonction asynchrone:

await lookUpVersion();

Pour utiliser await, le code doit être dans un async function - une fonction
marquée comme async:

Future checkVersion() async {


var version = await lookUpVersion();
// Do something with version
}

Remarque: Bien qu'une fonction asynchrone puisse effectuer des opérations fastidieuses, elle
n’attend pas l’exécution de ces opérations. Au lieu de cela, la fonction asynchrone s'exécute
uniquement jusqu'à ce qu'elle rencontre sa première instruction await (détails ). Ensuite, il
retourne un objet Future, et reprend l’exécution seulement après que l’expression await soit
terminée.

70
Utiliser try, catch, et finallypour gérer les erreurs et le nettoyage dans le code
qui utilise await:

try {
version = await lookUpVersion();
} catch (e) {
// React to inability to look up the version
}

Vous pouvez utiliser awaitplusieurs fois dans une fonction asynchrone. Par
exemple, le code suivant attend trois fois pour les résultats des fonctions:

var entrypoint = await findEntrypoint();


var exitCode = await runExecutable(entrypoint, args);
await flushThenExit(exitCode);

Dans l'expression await , la valeur de expressionest généralement un Future; si


ce n’est pas le cas, la valeur est automatiquement encapsulée dans un Future.
Cet objet Future indique une promesse de retourner un objet. La valeur
de l'expression await est cet objet retourné. L'expression await met l'exécution
en pause jusqu'à ce que l'objet soit disponible.

Si vous obtenez une erreur de compilation lors de l’utilisation de await,


assurez-vous que awaitest dans une fonction asynchrone. Par exemple,
pour utiliser awaitdans la fonction main() de votre application, le corps
de main() doit être marqué comme async:

Future main() async {


checkVersion();
print('In main: version is ${await lookUpVersion()}');
}

Déclarer des fonctions async


Une async functionest une fonction dont le corps est marqué par le mot
clé async.

Ajouter le mot clé async à une fonction lui fait retourner un Future. Par
exemple, considérons cette fonction synchrone, qui retourne une chaîne:

String lookUpVersion() => '1.0.0';

Si vous le changez en fonction asynchrone, par exemple, car une prochaine


version prendra beaucoup de temps, la la valeur renvoyée est un Future:

Future<String> lookUpVersion() async => '1.0.0';

71
Notez que le corps de la fonction n’a pas besoin d’utiliser l’API Future. Dart
crée l'objet Future si nécessaire.

Si votre fonction ne renvoie pas de valeur utile, faire lui retourner Future<void>.

Traitement des flux


Lorsque vous avez besoin d'obtenir des valeurs d'un flux, vous avez deux
options:

 Use async et une boucle for asynchrone (await for).


 Utilisez l'API Stream, comme décrit dans la visite de la bibliothèque .

Remarque: Avant d'utiliser await for, assurez-vous que cela rend le code plus clair et que
vous voulez vraiment attendre tous les résultats du flux. Par exemple, vous devriez
habituellement ne pas utiliser await forpour les listeners d'événements UI, parce que le
Framework UI envoie des flux infinis d’événements.

Une boucle for asynchrone a la forme suivante:

await for (varOrType identifier in expression) {


// Executes each time the stream emits a value.
}

La valeur d'expression doit avoir le type Stream. L'exécution se déroule comme


suit:

1. Attendez que le flux émette une valeur.


2. Exécuter le corps de la boucle for, avec la variable définie à cette valeur
émise.
3. Répétez les étapes 1 et 2 jusqu'à la fermeture du flux.

Pour arrêter d'écouter le flux, vous pouvez utiliser une


instruction break or return, qui sort de la boucle et se désabonner du flux.

Si vous obtenez une erreur de compilation lors de l'implémentation d'une


boucle for asynchrone, assurez-vous que le await forest dans une
fonction asynchrone. Par exemple, pour utiliser une boucle for asynchrone
dans la fonction main() de votre application, le corps de main() doit être
marqué comme async:

Future main() async {


// ...
await for (var request in requestServer) {
handleRequest(request);
}

72
// ...
}

Pour plus d’informations sur la programmation asynchrone, en général, voir la


section dart:async section de la visite de la bibliothèque.

Generators
Lorsque vous devez produire progressivement une séquence de valeurs,
envisager d'utiliser une fonction générateur . Dart prend en charge de manière
intégrée deux types de fonctions de générateur:

 Les générateurs synchrones qui retournent un objet Iterable.


 Les générateurs asynchrones qui retournent un objet Stream.

Pour mettre en place une fonction générateur synchrone , marquer le corps


de fonction comme sync*, et utilisez l'instruction yield pour delivrer des
valeurs:

Iterable<int> naturalsTo(int n) sync* {


int k = 0;
while (k < n) yield k++;
}

Pour mettre en place une fonction générateur asynchrone , marquer le corps


de fonction comme async*, et utilisez l'instruction yieldpour delivrer des
valeurs:

Stream<int> asynchronousNaturalsTo(int n) async* {


int k = 0;
while (k < n) yield k++;
}

Si votre générateur est récursif, vous pouvez améliorer ses performances en


utilisant yield*:

Iterable<int> naturalsDownFrom(int n) sync* {


if (n > 0) {
yield n;
yield* naturalsDownFrom(n - 1);
}
}

73
Les classes appelables
To allow an instance of your Dart class to be called like a function, implement
the call().

Dans l'exemple suivant, la classe WannabeFunction définit une fonction call ()


qui prend trois chaînes et les concatène, en les séparant par un espace et en

ajoutant une exclamation. Cliquez sur le bouton Exécuter pour exécuter le


code.

Isolates
La plupart des ordinateurs, même sur les plates-formes mobiles, ont des
processeurs multicœurs. Pour tirer parti de tous ces cœurs, les développeurs
utilisent traditionnellement threads de mémoire partagée s'exécutant
simultanément. Cependant, l'état partagé la concurrence est sujette aux
erreurs et peut conduire à un code compliqué.

Au lieu de threads, tout le code Dart s'exécute à l'intérieur d'isolats. Chaque


isolat a son propre tas de mémoire, garantissant qu'aucun état des isolat n'est
accessible depuis un autre isolat.

For more information, see the following:

 Dart asynchronous programming: Isolates and event loops


 dart:isolate API
reference, including Isolate.spawn() and TransferableTypedData
 Background parsing cookbook on the Flutter site

Typedefs
Dans Dart, les fonctions sont des objets, tout comme les chaînes et les
nombres sont objets. Un typedef, ou function-type alias, donne à une fonction
un nom que vous pouvez utiliser lors de la déclaration de champs ou faites
des retour. Un typedef conserve les informations de type lorsqu'un type de
fonction est affecté à une variable.

Considérez le code suivant, qui n’utilise pas de typedef:

class SortedCollection {
Function compare;

74
SortedCollection(int f(Object a, Object b)) {
compare = f;
}
}

// Initial, broken implementation.


int sort(Object a, Object b) => 0;

void main() {
SortedCollection coll = SortedCollection(sort);

// All we know is that compare is a function,


// but what type of function?
assert(coll.compare is Function);
}

Les informations de type sont perdues lors de l'attribution de f à compare. Le


type de f est (Object, Object) → int(où → signifie retourne), mais le Type
de compareest fonction. Si nous changeons le code pour utiliser explicitement
des noms et conserver les informations de type, les développeurs et les outils
pourraient utiliser cette information.

typedef Compare = int Function(Object a, Object b);

class SortedCollection {
Compare compare;

SortedCollection(this.compare);
}

// Initial, broken implementation.


int sort(Object a, Object b) => 0;

void main() {
SortedCollection coll = SortedCollection(sort);
assert(coll.compare is Function);
assert(coll.compare is Compare);
}

Note:Actuellement, les typedefs sont limités aux types de fonction. Cela pourrait changer.

Parce que les typedefs sont simplement des alias, ils offrent un moyen de
vérifier le type de toute fonction. Par exemple:

typedef Compare<T> = int Function(T a, T b);

int sort(int a, int b) => a - b;

75
void main() {
assert(sort is Compare<int>); // True!
}

Metadata
Utilisez les métadonnées pour donner des informations supplémentaires sur
votre code. Dans une métadonnée, l'annotation commence par le caractère @,
suivi soit d'une référence à une constante de compilation (telle que deprecated)
ou un appel à un constructeur constant.

Deux annotations sont disponibles pour tout le code


Dart: @deprecated and @override. Pour des exemples d'utilisation de @override,
voir Héritage de classe . Voici un exemple d'utilisation de @deprecated:

class Television {
/// _Deprecated: Use [turnOn] instead._
@deprecated
void activate() {
turnOn();
}

/// Turns the TV's power on.


void turnOn() {...}
}

Vous pouvez définir vos propres annotations de métadonnées. Voici un


exemple de définir une annotation @todo qui prend deux arguments:

library todo;

class Todo {
final String who;
final String what;

const Todo(this.who, this.what);


}

Et voici un exemple d'utilisation de cette annotation @todo:

import 'todo.dart';

@Todo('seth', 'make this do something')


void doSomething() {
print('do something');
76
}

Les métadonnées peuvent apparaître avant une bibliothèque, une classe, un


typedef, un paramètre de type, un constructeur, une fabrique, une fonction, un
champ, un paramètre ou une déclaration de variable et avant une directive
d'importation ou d'exportation. Vous pouvez récupérer des métadonnées au
moment de l'exécution à l'aide de la réflexion.

Comments
Dart prend en charge les commentaires sur une seule ligne, les commentaires
sur plusieurs lignes et commentaires de la documentation.

Commentaires sur une seule ligne


Un commentaire d'une seule ligne commence par //. Tout entre //et le la fin
de la ligne est ignorée par le compilateur Dart.

void main() {
// TODO: refactor into an AbstractLlamaGreetingFactory?
print('Welcome to my Llama farm!');
}

Commentaires multilignes
Un commentaire multiligne commence par /* et se termine par */. Tout
entre /* and */ est ignoré par le compilateur Dart (à moins que le commentaire
soit un commentaire de documentation; voir la section suivante). Les
commentaires multiligne peuvent nidifier.

void main() {
/*
* This is a lot of work. Consider raising chickens.

Llama larry = Llama();


larry.feed();
larry.exercise();
larry.clean();
*/
}

Commentaires de la documentation

77
Les commentaires de la documentation sont des commentaires multilignes ou
simples qui commencent avec /// or /**. En utilisez ///sur les lignes
consécutives a le même effet en tant que commentaire doc multi-lignes.

Dans un commentaire de documentation, le compilateur Dart ignore tout le


texte à moins qu'il ne soit entre crochets. En utilisant des parenthèses, vous
pouvez vous référer à classes, méthodes, champs, variables de niveau
supérieur, fonctions et paramètres. Les noms entre parenthèses sont résolus
dans la portée lexicale de l'élément de programme documenté.

Voici un exemple de commentaires de la documentation avec des références


à d’autres classes et arguments:

/// A domesticated South American camelid (Lama glama).


///
/// Andean cultures have used llamas as meat and pack
/// animals since pre-Hispanic times.
class Llama {
String name;

/// Feeds your llama [Food].


///
/// The typical llama eats one bale of hay per week.
void feed(Food food) {
// ...
}

/// Exercises your llama with an [activity] for


/// [timeLimit] minutes.
void exercise(Activity activity, int timeLimit) {
// ...
}
}

Dans la documentation générée, [Food] devient un lien vers la documentation


de l'API pour la classe alimentaire.

Pour analyser le code Dart et générer une documentation HTML, vous pouvez
utiliser le logiciel SDK. outil de génération de documentation. . Pour un
exemple de la documentation générée, voir la Documentation de l'API Dart.
Pour des conseils sur la façon de structurer vos commentaires,
voir Instructions pour les commentaires Dart Doc.

78
Summary
Cette page résume les fonctionnalités couramment utilisées dans le langage
Dart. Davantage de fonctionnalités seront mises en œuvre, mais nous nous
attendons à ce qu’elles ne cassent pas le code existant. Pour plus
d'informations, voir la Spécification du langage Dartand Dart efficace .

Pour en savoir plus sur les bibliothèques principales de Dart, voir Visite des
bibliothèques Dart.

79
Dart efficace
Contents

 Les guides
 Comment lire les guides
 Glossaire
 Résumé de toutes les règles
o Style
o Documentation
o Usage
o Conception

Au cours des dernières années, nous avons écrit une tonne de code Dart et avons beaucoup
appris à propos de ce qui fonctionne bien et de ce qui ne fonctionne pas. Nous partageons cela
avec vous pour que vous puissiez écrire aussi un code cohérent, robuste et rapide. Il y a deux
thèmes généraux:

1. Être cohérent. Lorsque tout devient compliqué et qu'on y comprend plus rien, le
mieux c'est encore d'être consistent. Cet objectif peut vous être utile !

Si deux morceaux de code semblent différents, cela devrait être parce


qu'ils sont différents d'une manière significative. Quand un peu de code se démarque
et attrape votre œil, il devrait le faire pour une raison utile.

2. Etre concis.Dart a été conçu pour être familier, il hérite donc de la plupart des mêmes
déclarations et expressions que C, Java, JavaScript et d’autres langages. Mais nous
avons créé Dart parce qu’il reste encore beaucoup à faire pour améliorer ce que offre
les langages. Nous avons ajouté de nombreuses fonctionnalités, pour vous aider à
exprimer votre intention le plus simplement et facilement.

S'il y a plusieurs façons de dire quelque chose, vous devriez généralement choisir le
plus concis. Cela ne veut pas dire que vous devriez participer au code golf et entasser
tout un programme dans une seule ligne. Le but est un code qu'il soit économique ,
mais pas dense.

The Dart analyzer has a linter to help you write good, consistent code. If a linter rule exists
that can help you follow a guideline, then the guideline links to that rule. Here’s an example:

Linter rule: prefer_collection_literals

For help on enabling linter rules, see the documentation for customizing static analysis.

80
The guides
Nous avons divisé les lignes directrices en quelques pages distinctes pour faciliter la
digestion:

 Guide de style- Ce guide définit les règles de mise en page et d'organisation du code,
ou au moins les parties que dartfmt ne gère pas pour vous. Le guide de style spécifie
également comment les identificateurs sont
formatés: camelCase, using_underscores, etc.
 Guide de documentation - Ce guide vous dit tout ce que vous avez besoin savoir sur
ce qui se passe à l'intérieur des commentaires. Les commentaires standards et les
commentaires de documentation, les commentaires de code usuels.
 Guide d'utilisation - Ce guide vous apprend à tirer le meilleur parti de fonctionnalités
du langage pour implémenter le comportement. Si c’est dans une déclaration ou
expression, c’est couvert ici.
 Guide de conception - C’est le guide le plus simple, mais celui avec la plus grande
portée. Il couvre ce que nous avons appris sur la conception API cohérentes et
utilisables pour les bibliothèques. Si c’est dans une signature de type ou déclaration,
cela passe dessus.

Pour des liens vers toutes les directives, voir le sommaire.

Comment lire les guides


Chaque guide est divisé en quelques sections. Les sections contiennent une liste de directives.
Chaque ligne directrice commence par l'un des mots suivants:

 A RESPECTER: ces directives décrivent les pratiques qui doivent toujours être
suivies. Il n'y a aucune raison valable de pas suivre ces directives !
 NE JAMAIS FAIRE: ces directives sont l'inverse des directives A RESPECTER: des
choses qui ne sont presque jamais bonnes idée.
 DE PREFERENCE: ces directives sont des pratiques que vous devriez suivre.
Cependant, là peut-être qu'il existe des circonstances où il est logique de faire
autrement. Assurez-vous juste comprendre toutes les implications avant d'ignorer la
directive lorsque vous le faites.
 A EVITER: ces directives sont les choses que vous ne devriez pas faire mais où il
peut y avoir de bonnes raisons à de rares occasions de le faire quand même.
 A CONSIDERER: ces directives sont des cas pratiques que vous pourrez suivre si
vous le désirez, selon les circonstances, vos habitudes et votre propre préférence.

Some guidelines describe an exception where the rule does not apply. When listed, the
exceptions may not be exhaustive—you might still need to use your judgement on other cases.

On dirait que la police va frapper à votre porte si vous ne respectez pas ces directives, mais les
choses ne sont pas aussi sombres. La plupart des lignes directrices présentées ici sont du bon
sens et nous sommes tous des gens raisonnables. Le but final est que votre code soit sympa,
lisible et maintenable.

81
Glossary
Pour garder les lignes directrices brèves, nous utilisons quelques termes abrégés pour faire
référence à différents éléments de Dart.

 A library memberis a top-level field, getter, setter, or function. Basically, anything at


the top level that isn’t a type.
 A class memberest un constructeur, un champ, un getter, un setter, une fonction ou
opérateur déclaré dans une classe. Les membres de la classe peuvent être des instances
ou des statiques, abstrait ou concret.
 A member is either a library member or a class member.
 A variable, when used generally, refers to top-level variables, parameters, and local
variables. It doesn’t include static or instance fields.
 A type is any named type declaration: a class, typedef, or enum.
 A property is a top-level variable, getter (inside a class or at the top level, instance or
static), setter (same), or field (instance or static). Roughly any “field-like” named
construct.

Résumé de toutes les règles


Style
Identifiants

 A RESPECTER: nommer les types en utilisant UpperCamelCase.


 DO name libraries, packages, directories, and source files
using lowercase_with_underscores.
 A RESPECTER: nommez les préfixes d'importation en
utilisant lowercase_with_underscores.
 A RESPECTER: nommez les autres identifiants à l'aide de lowerCamelCase.
 PREFER using lowerCamelCase for constant names.
 A RESPECTER: capitaliser les acronymes et les abréviations plus longs que deux lettres
comme des mots.
 DON’T use a leading underscore for identifiers that aren’t private.
 DON’T use prefix letters.

Ordonnancement

 A RESPECTER: placez les importations "dart:" avant les autres importations.


 A RESPECTER: placez les importations de "package:" avant les importations relatives.
 PREFER placing external “package:” imports before other imports.
 A RESPECTER: spécifiez les exportations dans une section distincte après toutes les
importations.
 A RESPECTER: trier les sections par ordre alphabétique.

82
Mise en forme

 A RESPECTER: formatez votre code en utilisant dartfmt.


 CONSIDER changing your code to make it more formatter-friendly.
 AVOID lines longer than 80 characters.
 DO use curly braces for all flow control statements.

Documentation
Commentaires

 A RESPECTER: formatez les commentaires comme des phrases.


 DON’T use block comments for documentation.

Commentaires de documentation

 A RESPECTER: utilisez /// pour commenter les membres et les types


 PREFER writing doc comments for public APIs.
 CONSIDER writing a library-level doc comment.
 CONSIDER writing doc comments for private APIs.
 A RESPECTER: commencez les commentaires de documentation avec un résumé en une
phrase.
 A RESPECTER: séparez la première phrase d'un commentaire de documentation du reste du
commentaire
 AVOID redundancy with the surrounding context.
 PREFER starting function or method comments with third-person verbs.
 PREFER starting variable, getter, or setter comments with noun phrases.
 PREFER starting library or type comments with noun phrases.
 CONSIDER including code samples in doc comments.
 A RESPECTER; utilisez les crochets dans les commentaires de la documentation pour faire
référence aux identifiants inclus dans la portée.
 A RESPECTER; utilisez de la prose pour expliquer les paramètres, les valeurs de retour et les
exceptions.
 A RESPECTER; mettez les commentaires de documentation avant les annotations de
métadonnées.

Markdown

 AVOID using markdown excessively.


 AVOID using HTML for formatting.
 PREFER backtick fences for code blocks.

Writing

 PREFER brevity.
 AVOID abbreviations and acronyms unless they are obvious.
 PREFER using “this” instead of “the” to refer to a member’s instance.

83
Usage
Bibliothèques

 DO use strings in part of directives.


 DON’T import libraries that are inside the src directory of another package.
 PREFER relative paths when importing libraries within your own package’s lib directory.

Booleans

 DO use ?? to convert null to a boolean value.

Les chaînes de caractères

 DO use adjacent strings to concatenate string literals.


 PREFER using interpolation to compose strings and values.
 AVOID using curly braces in interpolation when not needed.

Les collections

 DO use collection literals when possible.


 DON’T use .length to see if a collection is empty.
 CONSIDER using higher-order methods to transform a sequence.
 AVOID using Iterable.forEach() with a function literal.
 DON’T use List.from() unless you intend to change the type of the result.
 DO use whereType() to filter a collection by type.
 DON’T use cast() when a nearby operation will do.
 AVOID using cast().

Les fonctions

 DO use a function declaration to bind a function to a name.


 DON’T create a lambda when a tear-off will do.

Les paramètres

 DO use = to separate a named parameter from its default value.


 DON’T use an explicit default value of null.

Les variables

 DON’T explicitly initialize variables to null.


 AVOID storing what you can calculate.

Les membres

 DON’T wrap a field in a getter and setter unnecessarily.


 PREFER using a final field to make a read-only property.
 CONSIDER using => for simple members.
 DON’T use this. except to redirect to a named constructor or to avoid shadowing.

84
 DO initialize fields at their declaration when possible.

Les constructeurs

 DO use initializing formals when possible.


 DON’T type annotate initializing formals.
 DO use ; instead of {} for empty constructor bodies.
 DON’T use new.
 DON’T use const redundantly.

La gestion des erreurs

 AVOID catches without on clauses.


 DON’T discard errors from catches without on clauses.
 DO throw objects that implement Error only for programmatic errors.
 DON’T explicitly catch Error or types that implement it.
 DO use rethrow to rethrow a caught exception.

Asynchronisme

 PREFER async/await over using raw futures.


 DON’T use async when it has no useful effect.
 CONSIDER using higher-order methods to transform a stream.
 AVOID using Completer directly.
 DO test for Future<T> when disambiguating a FutureOr<T> whose type argument could
be Object.

Design
Les noms

 DO use terms consistently.


 AVOID abbreviations.
 PREFER putting the most descriptive noun last.
 CONSIDER making the code read like a sentence.
 PREFER a noun phrase for a non-boolean property or variable.
 PREFER a non-imperative verb phrase for a boolean property or variable.
 CONSIDER omitting the verb for a named boolean parameter.
 PREFER the “positive” name for a boolean property or variable.
 PREFER an imperative verb phrase for a function or method whose main purpose is a side
effect.
 PREFER a noun phrase or non-imperative verb phrase for a function or method if returning a
value is its primary purpose.
 CONSIDER an imperative verb phrase for a function or method if you want to draw attention
to the work it performs.
 AVOID starting a method name with get.
 PREFER naming a method to___() if it copies the object’s state to a new object.
 PREFER naming a method as___() if it returns a different representation backed by the
original object.
 AVOID describing the parameters in the function’s or method’s name.

85
 DO follow existing mnemonic conventions when naming type parameters.

Les bibliothèques

 PREFER making declarations private.


 CONSIDER declaring multiple classes in the same library.

Classes and mixins

 AVOID defining a one-member abstract class when a simple function will do.
 AVOID defining a class that contains only static members.
 AVOID extending a class that isn’t intended to be subclassed.
 DO document if your class supports being extended.
 AVOID implementing a class that isn’t intended to be an interface.
 DO document if your class supports being used as an interface.
 DO use mixin to define a mixin type.
 AVOID mixing in a type that isn’t intended to be a mixin.

Les constructeurs

 CONSIDER making your constructor const if the class supports it.

Members

 PREFER making fields and top-level variables final.


 DO use getters for operations that conceptually access properties.
 DO use setters for operations that conceptually change properties.
 DON’T define a setter without a corresponding getter.
 AVOID returning null from members whose return type is bool, double, int, or num.
 AVOID returning this from methods just to enable a fluent interface.

Les types

 PREFER type annotating public fields and top-level variables if the type isn’t obvious.
 CONSIDER type annotating private fields and top-level variables if the type isn’t obvious.
 AVOID type annotating initialized local variables.
 AVOID annotating inferred parameter types on function expressions.
 AVOID redundant type arguments on generic invocations.
 DO annotate when Dart infers the wrong type.
 PREFER annotating with dynamic instead of letting inference fail.
 PREFER signatures in function type annotations.
 DON’T specify a return type for a setter.
 DON’T use the legacy typedef syntax.
 PREFER inline function types over typedefs.
 CONSIDER using function type syntax for parameters.
 DO annotate with Object instead of dynamic to indicate any object is allowed.
 DO use Future<void> as the return type of asynchronous members that do not produce
values.
 AVOID using FutureOr<T> as a return type.

Les paramètres

86
 AVOID positional boolean parameters.
 AVOID optional positional parameters if the user may want to omit earlier parameters.
 AVOID mandatory parameters that accept a special “no argument” value.
 DO use inclusive start and exclusive end parameters to accept a range.

Égalité

 DO override hashCode if you override ==.


 DO make your == operator obey the mathematical rules of equality.
 AVOID defining custom equality for mutable classes.
 DON’T check for null in custom == operators.

87
A surprisingly important part of good code is good style. Consistent naming, ordering, and
formatting helps code that is the same lookthe same. It takes advantage of the powerful
pattern-matching hardware most of us have in our ocular systems. If we use a consistent style
across the entire Dart ecosystem, it makes it easier for all of us to learn from and contribute to
each others’ code.

Identifiers
Identifiers come in three flavors in Dart.

 UpperCamelCase names capitalize the first letter of each word, including the first.
 lowerCamelCase names capitalize the first letter of each word, except the first which
is always lowercase, even if it’s an acronym.
 lowercase_with_underscores use only lowercase letters, even for acronyms, and
separate words with _.

A RESPECTER: nommer les types en


utilisant UpperCamelCase.
Linter rule: camel_case_types

Classes, enums, typedefs, and type parameters should capitalize the first letter of each word
(including the first word), and use no separators.

class SliderMenu { ... }

class HttpRequest { ... }

typedef Predicate<T> = bool Function(T value);

This even includes classes intended to be used in metadata annotations.

class Foo {
const Foo([arg]);
}

@Foo(anArg)
class A { ... }

@Foo()
class B { ... }

If the annotation class’s constructor takes no parameters, you might want to create a
separate lowerCamelCase constant for it.

88
const foo = Foo();

@foo
class C { ... }

DO name libraries, packages,


directories, and source files
using lowercase_with_underscores.
Linter rules: library_names, file_names

Some file systems are not case-sensitive, so many projects require filenames to be all
lowercase. Using a separating character allows names to still be readable in that form. Using
underscores as the separator ensures that the name is still a valid Dart identifier, which may be
helpful if the language later supports symbolic imports.

library peg_parser.source_scanner;

import 'file_system.dart';
import 'slider_menu.dart';
library pegparser.SourceScanner;

import 'file-system.dart';
import 'SliderMenu.dart';

Remarque: This guideline specifies how to name a library if you choose to name it. It is fine
to omit the library directive in a file if you want.

A RESPECTER: nommez les préfixes


d'importation en
utilisant lowercase_with_underscores.
Linter rule: library_prefixes

import 'dart:math' as math;


import 'package:angular_components/angular_components'
as angular_components;
import 'package:js/js.dart' as js;
import 'dart:math' as Math;
import 'package:angular_components/angular_components'
as angularComponents;
import 'package:js/js.dart' as JS;

89
A RESPECTER: nommez les autres
identifiants à l'aide de lowerCamelCase.
Linter rule: non_constant_identifier_names

Class members, top-level definitions, variables, parameters, and named parameters should
capitalize the first letter of each word exceptthe first word, and use no separators.

var item;

HttpRequest httpRequest;

void align(bool clearItems) {


// ...
}

PREFER using lowerCamelCase for constant


names.
Linter rule: constant_identifier_names

In new code, use lowerCamelCase for constant variables, including enum values.

const pi = 3.14;
const defaultTimeout = 1000;
final urlScheme = RegExp('^([a-z]+):');

class Dice {
static final numberGenerator = Random();
}
const PI = 3.14;
const DefaultTimeout = 1000;
final URL_SCHEME = RegExp('^([a-z]+):');

class Dice {
static final NUMBER_GENERATOR = Random();
}

You may use SCREAMING_CAPS for consistency with existing code, as in the following cases:

 When adding code to a file or library that already uses SCREAMING_CAPS.


 When generating Dart code that’s parallel to Java code — for example, in enumerated types
generated from protobufs.

90
Remarque: We initially used Java’s SCREAMING_CAPS style for constants. We changed for a
few reasons:

 SCREAMING_CAPS looks bad for many cases, particularly enum values for things like CSS
colors.
 Constants are often changed to final non-const variables, which would necessitate a name
change.
 The values property automatically defined on an enum type is const and lowercase.

A RESPECTER: capitaliser les


acronymes et les abréviations plus
longs que deux lettres comme des
mots.
Capitalized acronyms can be hard to read, and multiple adjacent acronyms can lead to
ambiguous names. For example, given a name that starts with HTTPSFTP, there’s no way to
tell if it’s referring to HTTPS FTP or HTTP SFTP.

To avoid this, acronyms and abbreviations are capitalized like regular words, except for two-
letter acronyms. (Two-letter abbreviationslike ID and Mr. are still capitalized like words.)

HttpConnectionInfo
uiHandler
IOStream
HttpRequest
Id
DB
HTTPConnection
UiHandler
IoStream
HTTPRequest
ID
Db

DON’T use a leading underscore for


identifiers that aren’t private.
Dart uses a leading underscore in an identifier to mark members and top-level declarations as
private. This trains users to associate a leading underscore with one of those kinds of
declarations. They see “_” and think “private”.

There is no concept of “private” for local variables, parameters, or library prefixes. When one
of those has a name that starts with an underscore, it sends a confusing signal to the reader. To
avoid that, don’t use leading underscores in those names.
91
Exception: An unused parameter can be named _, __, ___, etc. This happens in things like
callbacks where you are passed a value but you don’t need to use it. Giving it a name that
consists solely of underscores is the idiomatic way to indicate the value isn’t used.

DON’T use prefix letters.


Hungarian notation and other schemes arose in the time of BCPL, when the compiler didn’t
do much to help you understand your code. Because Dart can tell you the type, scope,
mutability, and other properties of your declarations, there’s no reason to encode those
properties in identifier names.

defaultTimeout
kDefaultTimeout

Ordering
To keep the preamble of your file tidy, we have a prescribed order that directives should
appear in. Each “section” should be separated by a blank line.

A single linter rule handles all the ordering guidelines: directives_ordering.

A RESPECTER: placez les


importations "dart:" avant les autres
importations.
Linter rule: directives_ordering

import 'dart:async';
import 'dart:html';

import 'package:bar/bar.dart';
import 'package:foo/foo.dart';

A RESPECTER: placez les


importations de "package:" avant les
importations relatives.
Linter rule: directives_ordering

import 'package:bar/bar.dart';
import 'package:foo/foo.dart';

92
import 'util.dart';

PREFER placing external “package:”


imports before other imports.
Linter rule: directives_ordering

If you have a number of “package:” imports for your own package along with other external
packages, place yours in a separate section after the external ones.

import 'package:bar/bar.dart';
import 'package:foo/foo.dart';

import 'package:my_package/util.dart';

A RESPECTER: spécifiez les


exportations dans une section
distincte après toutes les
importations.
Linter rule: directives_ordering

import 'src/error.dart';
import 'src/foo_bar.dart';

export 'src/error.dart';
import 'src/error.dart';
export 'src/error.dart';
import 'src/foo_bar.dart';

A RESPECTER: trier les sections par


ordre alphabétique.
Linter rule: directives_ordering

import 'package:bar/bar.dart';
import 'package:foo/foo.dart';

import 'foo.dart';
import 'foo/foo.dart';
import 'package:foo/foo.dart';
93
import 'package:bar/bar.dart';

import 'foo/foo.dart';
import 'foo.dart';

Formatting
Like many languages, Dart ignores whitespace. However, humans don’t. Having a consistent
whitespace style helps ensure that human readers see code the same way the compiler does.

A RESPECTER: formatez votre code


en utilisant dartfmt.
Formatting is tedious work and is particularly time-consuming during refactoring.
Fortunately, you don’t have to worry about it. We provide a sophisticated automated code
formatter called dartfmt that does do it for you. We have some documentation on the rules it
applies, but the official whitespace-handling rules for Dart are whatever dartfmt produces.

The remaining formatting guidelines are for the few things dartfmt cannot fix for you.

CONSIDER changing your code to


make it more formatter-friendly.
The formatter does the best it can with whatever code you throw at it, but it can’t work
miracles. If your code has particularly long identifiers, deeply nested expressions, a mixture
of different kinds of operators, etc. the formatted output may still be hard to read.

When that happens, reorganize or simplify your code. Consider shortening a local variable
name or hoisting out an expression into a new local variable. In other words, make the same
kinds of modifications that you’d make if you were formatting the code by hand and trying to
make it more readable. Think of dartfmt as a partnership where you work together, sometimes
iteratively, to produce beautiful code.

AVOID lines longer than 80 characters.


Linter rule: lines_longer_than_80_chars

Readability studies show that long lines of text are harder to read because your eye has to
travel farther when moving to the beginning of the next line. This is why newspapers and
magazines use multiple columns of text.

If you really find yourself wanting lines longer than 80 characters, our experience is that your
code is likely too verbose and could be a little more compact. The main offender is

94
usually VeryLongCamelCaseClassNames. Ask yourself, “Does each word in that type name
tell me something critical or prevent a name collision?” If not, consider omitting it.

Note that dartfmt does 99% of this for you, but the last 1% is you. It does not split long string
literals to fit in 80 columns, so you have to do that manually.

Exception: When a URI or file path occurs in a comment or string (usually in an import or
export), it may remain whole even if it causes the line to go over 80 characters. This makes it
easier to search source files for a path.

Exception: Multi-line strings can contain lines longer than 80 characters because newlines
are significant inside the string and splitting the lines into shorter ones can alter the program.

DO use curly braces for all flow


control statements.
Linter rule: curly_braces_in_flow_control_structures

Doing so avoids the dangling else problem.

if (isWeekDay) {
print('Bike to work!');
} else {
print('Go dancing or read a book!');
}

Exception: When you have an if statement with no else clause and the whole if statement
fits on one line, you can omit the braces if you prefer:

if (arg == null) return defaultValue;

If the body wraps to the next line, though, use braces:

if (overflowChars != other.overflowChars) {
return overflowChars < other.overflowChars;
}
if (overflowChars != other.overflowChars)
return overflowChars < other.overflowChars;

 ⟨ Overview

95
Effective Dart:
Documentation
Contents

 Comments
o A RESPECTER: formatez les commentaires comme des phrases.
o DON’T use block comments for documentation.
 Doc comments
o DO use /// doc comments to document members and types.
o PREFER writing doc comments for public APIs.
o CONSIDER writing a library-level doc comment.
o CONSIDER writing doc comments for private APIs.
o A RESPECTER: commencez les commentaires de documentation
avec un résumé en une phrase.
o A RESPECTER: séparez la première phrase d'un commentaire
de documentation du reste du commentaire
o AVOID redundancy with the surrounding context.
o PREFER starting function or method comments with third-person
verbs.
o PREFER starting variable, getter, or setter comments with noun
phrases.
o PREFER starting library or type comments with noun phrases.
o CONSIDER including code samples in doc comments.
o DO use square brackets in doc comments to refer to in-scope
identifiers.
o DO use prose to explain parameters, return values, and
exceptions.
o DO put doc comments before metadata annotations.
 Markdown
o AVOID using markdown excessively.
o AVOID using HTML for formatting.
o PREFER backtick fences for code blocks.
 Writing
o PREFER brevity.
o AVOID abbreviations and acronyms unless they are obvious.
o PREFER using “this” instead of “the” to refer to a member’s
instance.

It’s easy to think your code is obvious today without realizing how much you
rely on context already in your head. People new to your code, and even your
forgetful future self won’t have that context. A concise, accurate comment only
takes a few seconds to write but can save one of those people hours of time.

96
We all know code should be self-documenting and not all comments are
helpful. But the reality is that most of us don’t write as many comments as we
should. It’s like exercise: you technically can do too much, but it’s a lot more
likely that you’re doing too little. Try to step it up.

commentaires
The following tips apply to comments that you don’t want included in the
generated documentation.

A RESPECTER: formatez les


commentaires comme des phrases.
// Not if there is nothing before it.
if (_chunks.isEmpty) return false;

Capitalize the first word unless it’s a case-sensitive identifier. End it with a
period (or “!” or “?”, I suppose). This is true for all comments: doc comments,
inline stuff, even TODOs. Even if it’s a sentence fragment.

DON’T use block comments for


documentation.
greet(name) {
// Assume we have a valid name.
print('Hi, $name!');
}
greet(name) {
/* Assume we have a valid name. */
print('Hi, $name!');
}

You can use a block comment (/* ... */) to temporarily comment out a
section of code, but all other comments should use //.

Doc comments
Doc comments are especially handy because dartdoc parses them and
generates beautiful doc pages from them. A doc comment is any comment
that appears before a declaration and uses the special /// syntax that dartdoc
looks for.

97
A RESPECTER: utilisez /// doc
comments to document members and
types.
Linter rule: slash_for_doc_comments

Using a doc comment instead of a regular comment enables dartdoc to find it


and generate documentation for it.

/// The number of characters in this chunk when unsplit.


int get length => ...
// The number of characters in this chunk when unsplit.
int get length => ...

For historical reasons, dartdoc supports two syntaxes of doc


comments: /// (“C# style”) and /** ... */ (“JavaDoc style”). We
prefer ///because it’s more compact. /** and */ add two content-free lines to
a multiline doc comment. The /// syntax is also easier to read in some
situations, such as when a doc comment contains a bulleted list that uses * to
mark list items.

If you stumble onto code that still uses the JavaDoc style, consider cleaning it
up.

PREFER writing doc comments for


public APIs.
Linter rules: package_api_docs, public_member_api_docs

You don’t have to document every single library, top-level variable, type, and
member, but you should document most of them.

CONSIDER writing a library-level doc


comment.
Unlike languages like Java where the class is the only unit of program
organization, in Dart, a library is itself an entity that users work with directly,
import, and think about. That makes the library directive a great place for
documentation that introduces the reader to the main concepts and
functionality provided within. Consider including:

98
 A single-sentence summary of what the library is for.
 Explanations of terminology used throughout the library.
 A couple of complete code samples that walk through using the API.
 Links to the most important or most commonly used classes and
functions.
 Links to external references on the domain the library is concerned with.

You document a library by placing a doc comment right above


the library directive at the start of the file. If the library doesn’t have
a library directive, you can add one just to hang the doc comment off of it.

CONSIDER writing doc comments for


private APIs.
Doc comments aren’t just for external consumers of your library’s public API.
They can also be helpful for understanding private members that are called
from other parts of the library.

A RESPECTER: commencez les


commentaires de documentation avec
un résumé en une phrase.
Start your doc comment with a brief, user-centric description ending with a
period. A sentence fragment is often sufficient. Provide just enough context for
the reader to orient themselves and decide if they should keep reading or look
elsewhere for the solution to their problem.

/// Deletes the file at [path] from the file system.


void delete(String path) {
...
}
/// Depending on the state of the file system and the
user's permissions,
/// certain operations may or may not be possible. If
there is no file at
/// [path] or it can't be accessed, this function throws
either [IOError]
/// or [PermissionError], respectively. Otherwise, this
deletes the file.
void delete(String path) {
...
}

99
A RESPECTER: séparez la première
phrase d'un commentaire de
documentation du reste du
commentaire
Add a blank line after the first sentence to split it out into its own paragraph. If
more than a single sentence of explanation is useful, put the rest in later
paragraphs.

This helps you write a tight first sentence that summarizes the documentation.
Also, tools like Dartdoc use the first paragraph as a short summary in places
like lists of classes and members.

/// Deletes the file at [path].


///
/// Throws an [IOError] if the file could not be found.
Throws a
/// [PermissionError] if the file is present but could not
be deleted.
void delete(String path) {
...
}
/// Deletes the file at [path]. Throws an [IOError] if the
file could not
/// be found. Throws a [PermissionError] if the file is
present but could
/// not be deleted.
void delete(String path) {
...
}

AVOID redundancy with the


surrounding context.
The reader of a class’s doc comment can clearly see the name of the class,
what interfaces it implements, etc. When reading docs for a member, the
signature is right there, and the enclosing class is obvious. None of that needs
to be spelled out in the doc comment. Instead, focus on explaining what the
reader doesn’t already know.

class RadioButtonWidget extends Widget {

100
/// Sets the tooltip to [lines], which should have been
word wrapped using
/// the current font.
void tooltip(List<String> lines) {
...
}
}
class RadioButtonWidget extends Widget {
/// Sets the tooltip for this radio button widget to the
list of strings in
/// [lines].
void tooltip(List<String> lines) {
...
}
}

PREFER starting function or method


comments with third-person verbs.
The doc comment should focus on what the code does.

/// Returns `true` if every element satisfies the


[predicate].
bool all(bool predicate(T element)) => ...

/// Starts the stopwatch if not already running.


void start() {
...
}

PREFER starting variable, getter, or


setter comments with noun phrases.
The doc comment should stress what the property is. This is true even for
getters which may do calculation or other work. What the caller cares about is
the result of that work, not the work itself.

/// The current day of the week, where `0` is Sunday.


int weekday;

/// The number of checked buttons on the page.


int get checkedCount => ...

101
Avoid having a doc comment on both the setter and the getter, as DartDoc will
show only one (the one on the getter.)

PREFER starting library or type


comments with noun phrases.
Doc comments for classes are often the most important documentation in your
program. They describe the type’s invariants, establish the terminology it uses,
and provide context to the other doc comments for the class’s members. A
little extra effort here can make all of the other members simpler to document.

/// A chunk of non-breaking output text terminated by a


hard or soft newline.
///
/// ...
class Chunk { ... }

CONSIDER including code samples in


doc comments.
/// Returns the lesser of two numbers.
///
/// ```dart
/// min(5, 3) == 3
/// ```
num min(num a, num b) => ...

Humans are great at generalizing from examples, so even a single code


sample makes an API easier to learn.

DO use square brackets in doc


comments to refer to in-scope
identifiers.
Linter rule: comment_references

If you surround things like variable, method, or type names in square brackets,
then dartdoc looks up the name and links to the relevant API docs.
Parentheses are optional, but can make it clearer when you’re referring to a
method or constructor.

/// Throws a [StateError] if ...


102
/// similar to [anotherMethod()], but ...

To link to a member of a specific class, use the class name and member
name, separated by a dot:

/// Similar to [Duration.inDays], but handles fractional


days.

The dot syntax can also be used to refer to named constructors. For the
unnamed constructor, put parentheses after the class name:

/// To create a point, call [Point()] or use


[Point.polar()] to ...

DO use prose to explain parameters,


return values, and exceptions.
Other languages use verbose tags and sections to describe what the
parameters and returns of a method are.

/// Defines a flag with the given name and abbreviation.


///
/// @param name The name of the flag.
/// @param abbr The abbreviation for the flag.
/// @returns The new flag.
/// @throws ArgumentError If there is already an option
with
/// the given name or abbreviation.
Flag addFlag(String name, String abbr) => ...

The convention in Dart is to integrate that into the description of the method
and highlight parameters using square brackets.

/// Defines a flag.


///
/// Throws an [ArgumentError] if there is already an
option named [name] or
/// there is already an option using abbreviation [abbr].
Returns the new flag.
Flag addFlag(String name, String abbr) => ...

DO put doc comments before


metadata annotations.
/// A button that can be flipped on and off.
103
@Component(selector: 'toggle')
class ToggleComponent {}
@Component(selector: 'toggle')
/// A button that can be flipped on and off.
class ToggleComponent {}

Markdown
You are allowed to use most markdown formatting in your doc comments and
dartdoc will process it accordingly using the markdown package.

There are tons of guides out there already to introduce you to Markdown. Its
universal popularity is why we chose it. Here’s just a quick example to give you
a flavor of what’s supported:

/// This is a paragraph of regular text.


///
/// This sentence has *two* _emphasized_ words (italics)
and **two**
/// __strong__ ones (bold).
///
/// A blank line creates a separate paragraph. It has some
`inline code`
/// delimited using backticks.
///
/// * Unordered lists.
/// * Look like ASCII bullet lists.
/// * You can also use `-` or `+`.
///
/// 1. Numbered lists.
/// 2. Are, well, numbered.
/// 1. But the values don't matter.
///
/// * You can nest lists too.
/// * They must be indented at least 4 spaces.
/// * (Well, 5 including the space after `///`.)
///
/// Code blocks are fenced in triple backticks:
///
/// ```
/// this.code
/// .will
/// .retain(its, formatting);
/// ```
///

104
/// The code language (for syntax highlighting) defaults
to Dart. You can
/// specify it by putting the name of the language after
the opening backticks:
///
/// ```html
/// <h1>HTML is magical!</h1>
/// ```
///
/// Links can be:
///
/// * http://www.just-a-bare-url.com
/// * [with the URL inline](http://google.com)
/// * [or separated out][ref link]
///
/// [ref link]: http://google.com
///
/// # A Header
///
/// ## A subheader
///
/// ### A subsubheader
///
/// #### If you need this many levels of headers, you're
doing it wrong

AVOID using markdown excessively.


When in doubt, format less. Formatting exists to illuminate your content, not
replace it. Words are what matter.

AVOID using HTML for formatting.


It may be useful to use it in rare cases for things like tables, but in almost all
cases, if it’s too complex too express in Markdown, you’re better off not
expressing it.

PREFER backtick fences for code


blocks.
Markdown has two ways to indicate a block of code: indenting the code four
spaces on each line, or surrounding it in a pair of triple-backtick “fence” lines.
The former syntax is brittle when used inside things like Markdown lists where

105
indentation is already meaningful or when the code block itself contains
indented code.

The backtick syntax avoids those indentation woes, lets you indicate the
code’s language, and is consistent with using backticks for inline code.

/// You can use [CodeBlockExample] like this:


///
/// ```
/// var example = CodeBlockExample();
/// print(example.isItGreat); // "Yes."
/// ```
/// You can use [CodeBlockExample] like this:
///
/// var example = CodeBlockExample();
/// print(example.isItGreat); // "Yes."

Writing
We think of ourselves as programmers, but most of the characters in a source
file are intended primarily for humans to read. English is the language we code
in to modify the brains of our coworkers. As for any programming language, it’s
worth putting effort into improving your proficiency.

This section lists a few guidelines for our docs. You can learn more about best
practices for technical writing, in general, from articles such as Technical
writing style.

PREFER brevity.
Be clear and precise, but also terse.

AVOID abbreviations and acronyms


unless they are obvious.
Many people don’t know what “i.e.”, “e.g.” and “et al.” mean. That acronym that
you’re sure everyone in your field knows may not be as widely known as you
think.

PREFER using “this” instead of “the”


to refer to a member’s instance.
106
When documenting a member for a class, you often need to refer back to the
object the member is being called on. Using “the” can be ambiguous.

class Box {
/// The value this wraps.
var _value;

/// True if this box contains a value.


bool get hasValue => _value != null;
}

107
A tour of the core libraries
Contents

 dart:core - nombres, collections, chaînes et plus


o Ecrire sur la console
o Les nombres
o Chaînes et expressions régulières
o Collections
o URIs
o Dates and times
o Utility classes
o Exceptions
 dart:async - asynchronous programming
o Future
o Stream
o Plus d'information
 dart:math - math and random
o Trigonometry
o Maximum and minimum
o Math constants
o Random numbers
o Plus d'information
 dart:convert - decoding and encoding JSON, UTF-8, and more
o Decoding and encoding JSON
o Decoding and encoding UTF-8 characters
o Other functionality
 dart:html - browser-based apps
o Manipulating the DOM
o Using HTTP resources with HttpRequest
o Sending and receiving real-time data with WebSockets
o Plus d'information
 dart:io - I/O for servers and command-line apps
o Files and directories
o HTTP clients and servers
o Plus d'information
 Résumé

This page shows you how to use the major features in Dart’s core libraries. It’s
just an overview, and by no means comprehensive. Whenever you need more
details about a class, consult the Dart API reference.

dart:core

108
Types intégrés, collections et autres fonctionnalités principales. Cette
bibliothèque est automatiquement importée dans chaque programme
Dart.

dart:async

Prise en charge de la programmation asynchrone, avec des classes


telles que Future et Stream.

dart:math

Constantes et fonctions mathématiques, plus un générateur de nombres


aléatoires.

dart:convert

Encodeurs et décodeurs pour la conversion entre différentes


représentations de données, notamment JSON et UTF-8.

dart:html

DOM and other APIs for browser-based apps.

dart:io

I/O for programs that can use the Dart VM, including Flutter apps,
servers, and command-line scripts.

This page is just an overview; it covers only a few dart:* libraries and no third-
party libraries.

Other places to find library information are the Pub site et le Dart web
developer library guide. You can find API documentation for all dart:* libraries
in the API Dart ou, si vous utilisez Flutter, la API Flutter.

Astuce DartPad: Vous pouvez jouer avec le code de cette page en le copiant dans un
fichier DartPad.

dart:core - nombres, collections,


chaînes et plus
La bibliothèque dart:core ( API reference) fournit un ensemble restreint mais
critique de fonctionnalités intégrées. Cette bibliothèque est automatiquement
importée dans chaque programme Dart.

109
Ecrire sur la console
La méthode globale print() prend un seul argument (de n'importe quel objet)
et affiche la valeur de chaîne de cet objet (telle que renvoyée par toString())
dans la console.

print(anObject);
print('I drink $tea.');

Pour plus d’informations sur les chaînes de base et toString(), voir Les
chaînes de caractères dans le tour de langue.

Numbers
La bibliothèque dart:core définit les classes num, int et double, qui offrent des
méthodes de base pour travailler avec des nombres.

Vous pouvez convertir une chaîne en un entier ou doubler avec la méthode


statique parse() de l'objet int ou double:

assert(int.parse('42') == 42);
assert(int.parse('0x42') == 66);
assert(double.parse('0.50') == 0.5);

Ou utilisez la méthode statique parse() de num, qui crée un entier si possible


et sinon un double:

assert(num.parse('42') is int);
assert(num.parse('0x42') is int);
assert(num.parse('0.50') is double);

Pour spécifier la base d'un entier, ajoutez un paramètre radix:

assert(int.parse('42', radix: 16) == 66);

Utilisez la méthode statique toString() pour convertir un int ou double à une


chaîne. Pour spécifier le nombre de chiffres à droite de la décimale,
utilisez toStringAsFixed().Pour spécifier le nombre de chiffres significatifs dans
la chaîne, utilisez toStringAsPrecision():

// Convert an int to a string.


assert(42.toString() == '42');

// Convert a double to a string.


assert(123.456.toString() == '123.456');

110
// Specify the number of digits after the decimal.
assert(123.456.toStringAsFixed(2) == '123.46');

// Specify the number of significant figures.


assert(123.456.toStringAsPrecision(2) == '1.2e+2');
assert(double.parse('1.2e+2') == 120.0);

Pour plus d'informations, voir la documentation de l'API


pour int, double, et num.. Voir aussi la section dart.math.

Chaînes et expressions régulières


Une chaîne dans Dart est une séquence immuable d'unités de code UTF-16.
La page Visite du langage Dart fournit plus d'information dans la section Les
chaînes de caractères. Vous pouvez utiliser des expressions régulières (objets
RegExp) pour rechercher dans les chaînes et remplacer des parties de
chaînes.

La classe String définit des méthodes telles


que split(), contains(), startsWith(), endsWith(), et bien d'autres.

Rechercher dans une chaîne


Vous pouvez trouver des emplacements particuliers dans une chaîne, ainsi
que vérifier si une chaîne commence ou se termine par un motif particulier.
Par Exemple:

// Check whether a string contains another string.


assert('Never odd or even'.contains('odd'));

// Does a string start with another string?


assert('Never odd or even'.startsWith('Never'));

// Does a string end with another string?


assert('Never odd or even'.endsWith('even'));

// Find the location of a string inside a string.


assert('Never odd or even'.indexOf('odd') == 6);

Extraire des données d'une chaîne


Vous pouvez obtenir les caractères ou les code UTF-16 d'une chaîne de
caractère, Un code UTF-16 est constitué de deux unités de code. Par

111
exemple, le symbole de la clé de sol ('\u{1D11E}') est composé deux unités de
code.

Vous pouvez également extraire une sous-chaîne ou scinder une chaîne en


une liste de sous-chaînes:

// Grab a substring.
assert('Never odd or even'.substring(6, 9) == 'odd');

// Split a string using a string pattern.


var parts = 'structured web apps'.split(' ');
assert(parts.length == 3);
assert(parts[0] == 'structured');

// Get a UTF-16 code unit (as a string) by index.


assert('Never odd or even'[0] == 'N');

// Use split() with an empty string parameter to get


// a list of all characters (as Strings); good for
// iterating.
for (var char in 'hello'.split('')) {
print(char);
}

// Get all the UTF-16 code units in the string.


var codeUnitList =
'Never odd or even'.codeUnits.toList();
assert(codeUnitList[0] == 78);

Conversion en majuscules ou minuscules


Vous pouvez facilement convertir les chaînes en majuscules et minuscules
variantes:

// Convert to uppercase.
assert('structured web apps'.toUpperCase() ==
'STRUCTURED WEB APPS');

// Convert to lowercase.
assert('STRUCTURED WEB APPS'.toLowerCase() ==
'structured web apps');

Remarque: Ces méthodes ne fonctionnent pas pour toutes les langues. Par
exemple, le turc l’alphabet sans points I is converted incorrectly.

Réduire et vider les chaînes


112
Supprimer tous les espaces blancs de début et de fin avec trim(). Vérifier si
une chaîne est vide (la longueur est zéro), utilisez isEmpty.

// Trim a string.
assert(' hello '.trim() == 'hello');

// Check whether a string is empty.


assert(''.isEmpty);

// Strings with only white space are not empty.


assert(' '.isNotEmpty);

Remplacement d'une partie d'une chaîne


Les chaînes sont des objets immuables, ce qui signifie que vous pouvez les
créer mais vous ne peux pas les changer. Si vous regardez de près l'API des
chaînes de caractères vous remarquerez qu'aucune des méthodes ne change
réellement l'état d'une chaîne. Par exemple, la méthode replaceAll() retourne
une nouvelle chaîne sans changer le Corde d'origine:

var greetingTemplate = 'Hello, NAME!';


var greeting =
greetingTemplate.replaceAll(RegExp('NAME'), 'Bob');

// greetingTemplate didn't change.


assert(greeting != greetingTemplate);

Building a string
To programmatically generate a string, you can use StringBuffer. A
StringBuffer doesn’t generate a new String object until toString() is called.
The writeAll() method has an optional second parameter that lets you specify
a separator—in this case, a space.

var sb = StringBuffer();
sb
..write('Use a StringBuffer for ')
..writeAll(['efficient', 'string', 'creation'], ' ')
..write('.');

var fullString = sb.toString();

assert(fullString ==
'Use a StringBuffer for efficient string creation.');

Regular expressions
113
The RegExp class provides the same capabilities as JavaScript regular
expressions. Use regular expressions for efficient searching and pattern
matching of strings.

// Here's a regular expression for one or more digits.


var numbers = RegExp(r'\d+');

var allCharacters = 'llamas live fifteen to twenty years';


var someDigits = 'llamas live 15 to 20 years';

// contains() can use a regular expression.


assert(!allCharacters.contains(numbers));
assert(someDigits.contains(numbers));

// Replace every match with another string.


var exedOut = someDigits.replaceAll(numbers, 'XX');
assert(exedOut == 'llamas live XX to XX years');

You can work directly with the RegExp class, too. The Match class provides
access to a regular expression match.

var numbers = RegExp(r'\d+');


var someDigits = 'llamas live 15 to 20 years';

// Check whether the reg exp has a match in a string.


assert(numbers.hasMatch(someDigits));

// Loop through all matches.


for (var match in numbers.allMatches(someDigits)) {
print(match.group(0)); // 15, then 20
}

Plus d'information
Refer to the String API reference for a full list of methods. Also see the API
reference for StringBuffer, Pattern, RegExp, and Match.

Collections
Dart ships with a core collections API, which includes classes for lists, sets,
and maps.

Les listes

114
As the language tour shows, you can use literals to create and initialize lists.
Alternatively, use one of the List constructors. The List class also defines
several methods for adding items to and removing items from lists.

// Use a List constructor.


var vegetables = List();

// Or simply use a list literal.


var fruits = ['apples', 'oranges'];

// Add to a list.
fruits.add('kiwis');

// Add multiple items to a list.


fruits.addAll(['grapes', 'bananas']);

// Get the list length.


assert(fruits.length == 5);

// Remove a single item.


var appleIndex = fruits.indexOf('apples');
fruits.removeAt(appleIndex);
assert(fruits.length == 4);

// Remove all elements from a list.


fruits.clear();
assert(fruits.isEmpty);

Use indexOf() to find the index of an object in a list:

var fruits = ['apples', 'oranges'];

// Access a list item by index.


assert(fruits[0] == 'apples');

// Find an item in a list.


assert(fruits.indexOf('apples') == 0);

Sort a list using the sort() method. You can provide a sorting function that
compares two objects. This sorting function must return < 0 for smaller, 0 for
the same, and > 0 for bigger. The following example uses compareTo(), which
is defined by Comparable and implemented by String.

var fruits = ['bananas', 'apples', 'oranges'];

// Sort a list.
fruits.sort((a, b) => a.compareTo(b));

115
assert(fruits[0] == 'apples');

Lists are parameterized types, so you can specify the type that a list should
contain:

// This list should contain only strings.


var fruits = List<String>();

fruits.add('apples');
var fruit = fruits[0];
assert(fruit is String);
fruits.add(5); // Error: 'int' can't be assigned to
'String'

Refer to the List API reference for a full list of methods.

Sets
A set in Dart is an unordered collection of unique items. Because a set is
unordered, you can’t get a set’s items by index (position).

var ingredients = Set();


ingredients.addAll(['gold', 'titanium', 'xenon']);
assert(ingredients.length == 3);

// Adding a duplicate item has no effect.


ingredients.add('gold');
assert(ingredients.length == 3);

// Remove an item from a set.


ingredients.remove('gold');
assert(ingredients.length == 2);

Use contains() and containsAll() to check whether one or more objects are in
a set:

var ingredients = Set();


ingredients.addAll(['gold', 'titanium', 'xenon']);

// Check whether an item is in the set.


assert(ingredients.contains('titanium'));

// Check whether all the items are in the set.


assert(ingredients.containsAll(['titanium', 'xenon']));

An intersection is a set whose items are in two other sets.

116
var ingredients = Set();
ingredients.addAll(['gold', 'titanium', 'xenon']);

// Create the intersection of two sets.


var nobleGases = Set.from(['xenon', 'argon']);
var intersection = ingredients.intersection(nobleGases);
assert(intersection.length == 1);
assert(intersection.contains('xenon'));

Refer to the Set API reference for a full list of methods.

Maps
A map, commonly known as a dictionary or hash, is an unordered collection of
key-value pairs. Maps associate a key to some value for easy retrieval. Unlike
in JavaScript, Dart objects are not maps.

You can declare a map using a terse literal syntax, or you can use a traditional
constructor:

// Maps often use strings as keys.


var hawaiianBeaches = {
'Oahu': ['Waikiki', 'Kailua', 'Waimanalo'],
'Big Island': ['Wailea Bay', 'Pololu Beach'],
'Kauai': ['Hanalei', 'Poipu']
};

// Maps can be built from a constructor.


var searchTerms = Map();

// Maps are parameterized types; you can specify what


// types the key and value should be.
var nobleGases = Map<int, String>();

You add, get, and set map items using the bracket syntax. Use remove() to
remove a key and its value from a map.

var nobleGases = {54: 'xenon'};

// Retrieve a value with a key.


assert(nobleGases[54] == 'xenon');

// Check whether a map contains a key.


assert(nobleGases.containsKey(54));

// Remove a key and its value.

117
nobleGases.remove(54);
assert(!nobleGases.containsKey(54));

You can retrieve all the values or all the keys from a map:

var hawaiianBeaches = {
'Oahu': ['Waikiki', 'Kailua', 'Waimanalo'],
'Big Island': ['Wailea Bay', 'Pololu Beach'],
'Kauai': ['Hanalei', 'Poipu']
};

// Get all the keys as an unordered collection


// (an Iterable).
var keys = hawaiianBeaches.keys;

assert(keys.length == 3);
assert(Set.from(keys).contains('Oahu'));

// Get all the values as an unordered collection


// (an Iterable of Lists).
var values = hawaiianBeaches.values;
assert(values.length == 3);
assert(values.any((v) => v.contains('Waikiki')));

To check whether a map contains a key, use containsKey(). Because map


values can be null, you cannot rely on simply getting the value for the key and
checking for null to determine the existence of a key.

var hawaiianBeaches = {
'Oahu': ['Waikiki', 'Kailua', 'Waimanalo'],
'Big Island': ['Wailea Bay', 'Pololu Beach'],
'Kauai': ['Hanalei', 'Poipu']
};

assert(hawaiianBeaches.containsKey('Oahu'));
assert(!hawaiianBeaches.containsKey('Florida'));

Use the putIfAbsent() method when you want to assign a value to a key if and
only if the key does not already exist in a map. You must provide a function
that returns the value.

var teamAssignments = {};


teamAssignments.putIfAbsent(
'Catcher', () => pickToughestKid());
assert(teamAssignments['Catcher'] != null);

Refer to the Map API reference for a full list of methods.

118
Common collection methods
List, Set, and Map share common functionality found in many collections.
Some of this common functionality is defined by the Iterable class, which List
and Set implement.

Remarque: Although Map doesn’t implement Iterable, you can get Iterables
from it using the Map keys and values properties.

Use isEmpty or isNotEmpty to check whether a list, set, or map has items:

var coffees = [];


var teas = ['green', 'black', 'chamomile', 'earl grey'];
assert(coffees.isEmpty);
assert(teas.isNotEmpty);

To apply a function to each item in a list, set, or map, you can use forEach():

var teas = ['green', 'black', 'chamomile', 'earl grey'];

teas.forEach((tea) => print('I drink $tea'));

When you invoke forEach() on a map, your function must take two arguments
(the key and value):

hawaiianBeaches.forEach((k, v) {
print('I want to visit $k and swim at $v');
// I want to visit Oahu and swim at
// [Waikiki, Kailua, Waimanalo], etc.
});

Iterables provide the map() method, which gives you all the results in a single
object:

var teas = ['green', 'black', 'chamomile', 'earl grey'];

var loudTeas = teas.map((tea) => tea.toUpperCase());


loudTeas.forEach(print);

Note: The object returned by map() is an Iterable that’s lazily evaluated: your
function isn’t called until you ask for an item from the returned object.

To force your function to be called immediately on each item,


use map().toList() or map().toSet():

var loudTeas =

119
teas.map((tea) => tea.toUpperCase()).toList();

Use Iterable’s where() method to get all the items that match a condition. Use
Iterable’s any() and every() methods to check whether some or all items match
a condition.

var teas = ['green', 'black', 'chamomile', 'earl grey'];

// Chamomile is not caffeinated.


bool isDecaffeinated(String teaName) =>
teaName == 'chamomile';

// Use where() to find only the items that return true


// from the provided function.
var decaffeinatedTeas =
teas.where((tea) => isDecaffeinated(tea));
// or teas.where(isDecaffeinated)

// Use any() to check whether at least one item in the


// collection satisfies a condition.
assert(teas.any(isDecaffeinated));

// Use every() to check whether all the items in a


// collection satisfy a condition.
assert(!teas.every(isDecaffeinated));

For a full list of methods, refer to the Iterable API reference, as well as those
for List, Set, and Map.

URIs
The Uri class provides functions to encode and decode strings for use in URIs
(which you might know as URLs). These functions handle characters that are
special for URIs, such as & and =. The Uri class also parses and exposes the
components of a URI—host, port, scheme, and so on.

Encoding and decoding fully qualified URIs


To encode and decode characters except those with special meaning in a URI
(such as /, :, &, #), use the encodeFull() anddecodeFull() methods. These
methods are good for encoding or decoding a fully qualified URI, leaving intact
special URI characters.

var uri = 'http://example.org/api?foo=some message';

120
var encoded = Uri.encodeFull(uri);
assert(encoded ==
'http://example.org/api?foo=some%20message');

var decoded = Uri.decodeFull(encoded);


assert(uri == decoded);

Notice how only the space between some and message was encoded.

Encoding and decoding URI components


To encode and decode all of a string’s characters that have special meaning in
a URI, including (but not limited to) /, &, and :, use
the encodeComponent() and decodeComponent() methods.

var uri = 'http://example.org/api?foo=some message';

var encoded = Uri.encodeComponent(uri);


assert(encoded ==

'http%3A%2F%2Fexample.org%2Fapi%3Ffoo%3Dsome%20message');

var decoded = Uri.decodeComponent(encoded);


assert(uri == decoded);

Notice how every special character is encoded. For example, / is encoded


to %2F.

Parsing URIs
If you have a Uri object or a URI string, you can get its parts using Uri fields
such as path. To create a Uri from a string, use the parse()static method:

var uri =
Uri.parse('http://example.org:8080/foo/bar#frag');

assert(uri.scheme == 'http');
assert(uri.host == 'example.org');
assert(uri.path == '/foo/bar');
assert(uri.fragment == 'frag');
assert(uri.origin == 'http://example.org:8080');

See the Uri API reference for more URI components that you can get.

Building URIs
121
You can build up a URI from individual parts using the Uri() constructor:

var uri = Uri(


scheme: 'http',
host: 'example.org',
path: '/foo/bar',
fragment: 'frag');
assert(
uri.toString() == 'http://example.org/foo/bar#frag');

Dates and times


A DateTime object is a point in time. The time zone is either UTC or the local
time zone.

You can create DateTime objects using several constructors:

// Get the current date and time.


var now = DateTime.now();

// Create a new DateTime with the local time zone.


var y2k = DateTime(2000); // January 1, 2000

// Specify the month and day.


y2k = DateTime(2000, 1, 2); // January 2, 2000

// Specify the date as a UTC time.


y2k = DateTime.utc(2000); // 1/1/2000, UTC

// Specify a date and time in ms since the Unix epoch.


y2k = DateTime.fromMillisecondsSinceEpoch(946684800000,
isUtc: true);

// Parse an ISO 8601 date.


y2k = DateTime.parse('2000-01-01T00:00:00Z');

The millisecondsSinceEpoch property of a date returns the number of


milliseconds since the “Unix epoch”—January 1, 1970, UTC:

// 1/1/2000, UTC
var y2k = DateTime.utc(2000);
assert(y2k.millisecondsSinceEpoch == 946684800000);

// 1/1/1970, UTC
var unixEpoch = DateTime.utc(1970);
assert(unixEpoch.millisecondsSinceEpoch == 0);

122
Use the Duration class to calculate the difference between two dates and to
shift a date forward or backward:

var y2k = DateTime.utc(2000);

// Add one year.


var y2001 = y2k.add(Duration(days: 366));
assert(y2001.year == 2001);

// Subtract 30 days.
var december2000 = y2001.subtract(Duration(days: 30));
assert(december2000.year == 2000);
assert(december2000.month == 12);

// Calculate the difference between two dates.


// Returns a Duration object.
var duration = y2001.difference(y2k);
assert(duration.inDays == 366); // y2k was a leap year.

Warning: Using a Duration to shift a DateTime by days can be problematic,


due to clock shifts (to daylight saving time, for example). Use UTC dates if you
must shift days.

For a full list of methods, refer to the API reference for DateTime and Duration.

Utility classes
The core library contains various utility classes, useful for sorting, mapping
values, and iterating.

Comparing objects
Implement the Comparable interface to indicate that an object can be
compared to another object, usually for sorting. The compareTo()method
returns < 0 for smaller, 0 for the same, and > 0 for bigger.

class Line implements Comparable<Line> {


final int length;
const Line(this.length);

@override
int compareTo(Line other) => length - other.length;
}

void main() {
var short = const Line(1);
123
var long = const Line(100);
assert(short.compareTo(long) < 0);
}

Implémentation des tableaux associatifs


Each object in Dart automatically provides an integer hash code, and thus can
be used as a key in a map. However, you can override thehashCode getter to
generate a custom hash code. If you do, you might also want to override
the == operator. Objects that are equal (via==) must have identical hash codes.
A hash code doesn’t have to be unique, but it should be well distributed.

class Person {
final String firstName, lastName;

Person(this.firstName, this.lastName);

// Override hashCode using strategy from Effective Java,


// Chapter 11.
@override
int get hashCode {
int result = 17;
result = 37 * result + firstName.hashCode;
result = 37 * result + lastName.hashCode;
return result;
}

// You should generally implement operator == if you


// override hashCode.
@override
bool operator ==(dynamic other) {
if (other is! Person) return false;
Person person = other;
return (person.firstName == firstName &&
person.lastName == lastName);
}
}

void main() {
var p1 = Person('Bob', 'Smith');
var p2 = Person('Bob', 'Smith');
var p3 = 'not a person';
assert(p1.hashCode == p2.hashCode);
assert(p1 == p2);
assert(p1 != p3);
}

124
Iteration
The Iterable and Iterator classes support for-in loops. Extend (if possible) or
implement Iterable whenever you create a class that can provide Iterators for
use in for-in loops. Implement Iterator to define the actual iteration ability.

class Process {
// Represents a process...
}

class ProcessIterator implements Iterator<Process> {


@override
Process get current => ...
@override
bool moveNext() => ...
}

// A mythical class that lets you iterate through all


// processes. Extends a subclass of [Iterable].
class Processes extends IterableBase<Process> {
@override
final Iterator<Process> iterator = ProcessIterator();
}

void main() {
// Iterable objects can be used with for-in.
for (var process in Processes()) {
// Do something with the process.
}
}

Les exceptions
The Dart core library defines many common exceptions and errors. Exceptions
are considered conditions that you can plan ahead for and catch. Errors are
conditions that you don’t expect or plan for.

A couple of the most common errors are:

NoSuchMethodError

Thrown when a receiving object (which might be null) does not


implement a method.

ArgumentError

125
Can be thrown by a method that encounters an unexpected argument.

Throwing an application-specific exception is a common way to indicate that


an error has occurred. You can define a custom exception by implementing
the Exception interface:

class FooException implements Exception {


final String msg;

const FooException([this.msg]);

@override
String toString() => msg ?? 'FooException';
}

For more information, see Exceptions (in the language tour) and the Exception
API reference.

dart:async - asynchronous
programming
Asynchronous programming often uses callback functions, but Dart provides
alternatives: Future and Stream objects. A Future is like a promise for a result
to be provided sometime in the future. A Stream is a way to get a sequence of
values, such as events. Future, Stream, and more are in the dart:async library
(API reference).

Note: You don’t always need to use the Future or Stream APIs directly. The
Dart language supports asynchronous coding using keywords such
as async and await. See Asynchronisme in the language tour for details.

The dart:async library works in both web apps and command-line apps. To
use it, import dart:async:

import 'dart:async';

Note de version: As of Dart 2.1, you don’t need to import dart:async to use the Future and
Stream APIs, because dart:core exports those classes.

Future

126
Future objects appear throughout the Dart libraries, often as the object
returned by an asynchronous method. When a future completes, its value is
ready to use.

Using await
Before you directly use the Future API, consider using await instead. Code that
uses await expressions can be easier to understand than code that uses the
Future API.

Consider the following function. It uses Future’s then() method to execute


three asynchronous functions in a row, waiting for each one to complete
before executing the next one.

runUsingFuture() {
// ...
findEntryPoint().then((entryPoint) {
return runExecutable(entryPoint, args);
}).then(flushThenExit);
}

The equivalent code with await expressions looks more like synchronous
code:

runUsingAsyncAwait() async {
// ...
var entryPoint = await findEntryPoint();
var exitCode = await runExecutable(entryPoint, args);
await flushThenExit(exitCode);
}

An async function can catch exceptions from Futures. For example:

var entryPoint = await findEntryPoint();


try {
var exitCode = await runExecutable(entryPoint, args);
await flushThenExit(exitCode);
} catch (e) {
// Handle the error...
}

Important: Async functions return Futures. If you don’t want your function to
return a future, then use a different solution. For example, you might call an
async function from your function.

127
For more information on using await and related Dart language features,
see Asynchronisme .

Basic usage
You can use then() to schedule code that runs when the future completes. For
example, HttpRequest.getString() returns a Future, since HTTP requests can
take a while. Using then() lets you run some code when that Future has
completed and the promised string value is available:

HttpRequest.getString(url).then((String result) {
print(result);
});

Use catchError() to handle any errors or exceptions that a Future object might
throw.

HttpRequest.getString(url).then((String result) {
print(result);
}).catchError((e) {
// Handle or ignore the error.
});

The then().catchError() pattern is the asynchronous version of try-catch.

Important: Be sure to invoke catchError() on the result of then()—not on the


result of the original Future. Otherwise, the catchError() can handle errors only
from the original Future’s computation, but not from the handler registered
by then().

Chaining multiple asynchronous methods


The then() method returns a Future, providing a useful way to run multiple
asynchronous functions in a certain order. If the callback registered
with then() returns a Future, then() returns an equivalent Future. If the
callback returns a value of any other type, then()creates a new Future that
completes with the value.

Future result = costlyQuery(url);


result
.then((value) => expensiveWork(value))
.then((_) => lengthyComputation())
.then((_) => print('Done!'))
.catchError((exception) {
/* Handle exception... */

128
});

In the preceding example, the methods run in the following order:

1. costlyQuery()
2. expensiveWork()
3. lengthyComputation()

Here is the same code written using await:

try {
final value = await costlyQuery(url);
await expensiveWork(value);
await lengthyComputation();
print('Done!');
} catch (e) {
/* Handle exception... */
}

Waiting for multiple futures


Sometimes your algorithm needs to invoke many asynchronous functions and
wait for them all to complete before continuing. Use the Future.wait() static
method to manage multiple Futures and wait for them to complete:

Future deleteLotsOfFiles() async => ...


Future copyLotsOfFiles() async => ...
Future checksumLotsOfOtherFiles() async => ...

await Future.wait([
deleteLotsOfFiles(),
copyLotsOfFiles(),
checksumLotsOfOtherFiles(),
]);
print('Done with all the long steps!');

Stream
Stream objects appear throughout Dart APIs, representing sequences of data.
For example, HTML events such as button clicks are delivered using streams.
You can also read a file as a stream.

Using an asynchronous for loop


Sometimes you can use an asynchronous for loop (await for) instead of using
the Stream API.
129
Consider the following function. It uses Stream’s listen() method to subscribe
to a list of files, passing in a function literal that searches each file or directory.

void main(List<String> arguments) {


// ...
FileSystemEntity.isDirectory(searchPath).then((isDir) {
if (isDir) {
final startingDir = Directory(searchPath);
startingDir
.list(
recursive: argResults[recursive],
followLinks: argResults[followLinks])
.listen((entity) {
if (entity is File) {
searchFile(entity, searchTerms);
}
});
} else {
searchFile(File(searchPath), searchTerms);
}
});
}

The equivalent code with await expressions, including an asynchronous for


loop (await for), looks more like synchronous code:

Future main(List<String> arguments) async {


// ...
if (await FileSystemEntity.isDirectory(searchPath)) {
final startingDir = Directory(searchPath);
await for (var entity in startingDir.list(
recursive: argResults[recursive],
followLinks: argResults[followLinks])) {
if (entity is File) {
searchFile(entity, searchTerms);
}
}
} else {
searchFile(File(searchPath), searchTerms);
}
}

Important: Before using await for, make sure that it makes the code clearer
and that you really do want to wait for all of the stream’s results. For example,
you usually should not use await for for DOM event listeners, because the
DOM sends endless streams of events. If you use await for to register two
DOM event listeners in a row, then the second kind of event is never handled.

130
For more information on using await and related Dart language features,
see Asynchronisme .

Listening for stream data


To get each value as it arrives, either use await for or subscribe to the stream
using the listen() method:

// Find a button by ID and add an event handler.


querySelector('#submitInfo').onClick.listen((e) {
// When the button is clicked, it runs this code.
submitData();
});

In this example, the onClick property is a Stream object provided by the


“submitInfo” button.

If you care about only one event, you can get it using a property such
as first, last, or single. To test the event before handling it, use a method
such as firstWhere(), lastWhere(), or singleWhere().

If you care about a subset of events, you can use methods such
as skip(), skipWhile(), take(), takeWhile(), and where().

Transforming stream data


Often, you need to change the format of a stream’s data before you can use it.
Use the transform() method to produce a stream with a different type of data:

var lines = inputStream


.transform(utf8.decoder)
.transform(LineSplitter());

This example uses two transformers. First it uses utf8.decoder to transform the
stream of integers into a stream of strings. Then it uses a LineSplitter to
transform the stream of strings into a stream of separate lines. These
transformers are from the dart:convert library (see the dart:convert section).

Handling errors and completion


How you specify error and completion handling code depends on whether you
use an asynchronous for loop (await for) or the Stream API.

If you use an asynchronous for loop, then use try-catch to handle errors. Code
that executes after the stream is closed goes after the asynchronous for loop.

131
Future readFileAwaitFor() async {
var config = File('config.txt');
Stream<List<int>> inputStream = config.openRead();

var lines = inputStream


.transform(utf8.decoder)
.transform(LineSplitter());
try {
await for (var line in lines) {
print('Got ${line.length} characters from stream');
}
print('file is now closed');
} catch (e) {
print(e);
}
}

If you use the Stream API, then handle errors by registering


an onError listener. Run code after the stream is closed by registering
an onDone listener.

var config = File('config.txt');


Stream<List<int>> inputStream = config.openRead();

inputStream
.transform(utf8.decoder)
.transform(LineSplitter())
.listen((String line) {
print('Got ${line.length} characters from stream');
}, onDone: () {
print('file is now closed');
}, onError: (e) {
print(e);
});

Plus d'information
For some examples of using Future and Stream in command-line apps, see
the Visite de dart:io. Also see these articles and tutorials:

 Asynchronous Programming: Futures


 Futures and Error Handling
 Programmation Asynchrone: Streams
 Creating Streams in Dart
 Dart asynchronous programming: Isolates and event loops

132
dart:math - math and random
The dart:math library (API reference) provides common functionality such as
sine and cosine, maximum and minimum, and constants such as pi and e.
Most of the functionality in the Math library is implemented as top-level
functions.

To use this library in your app, import dart:math.

import 'dart:math';

Trigonometry
The Math library provides basic trigonometric functions:

// Cosine
assert(cos(pi) == -1.0);

// Sine
var degrees = 30;
var radians = degrees * (pi / 180);
// radians is now 0.52359.
var sinOf30degrees = sin(radians);
// sin 30° = 0.5
assert((sinOf30degrees - 0.5).abs() < 0.01);

Note: These functions use radians, not degrees!

Maximum and minimum


The Math library provides max() and min() methods:

assert(max(1, 1000) == 1000);


assert(min(1, -1000) == -1000);

Math constants
Find your favorite constants—pi, e, and more—in the Math library:

// See the Math library for additional constants.


print(e); // 2.718281828459045
print(pi); // 3.141592653589793
print(sqrt2); // 1.4142135623730951

133
Random numbers
Generate random numbers with the Random class. You can optionally provide
a seed to the Random constructor.

var random = Random();


random.nextDouble(); // Between 0.0 and 1.0: [0, 1)
random.nextInt(10); // Between 0 and 9.

You can even generate random booleans:

var random = Random();


random.nextBool(); // true or false

Plus d'information
Refer to the Math API reference for a full list of methods. Also see the API
reference for num, int, and double.

dart:convert - decoding and


encoding JSON, UTF-8, and more
The dart:convert library (API reference) has converters for JSON and UTF-8,
as well as support for creating additional converters. JSON is a simple text
format for representing structured objects and collections. UTF-8 is a common
variable-width encoding that can represent every character in the Unicode
character set.

The dart:convert library works in both web apps and command-line apps. To
use it, import dart:convert.

import 'dart:convert';

Decoding and encoding JSON


Decode a JSON-encoded string into a Dart object with jsonDecode():

// NOTE: Be sure to use double quotes ("),


// not single quotes ('), inside the JSON string.
// This string is JSON, not Dart.
var jsonString = '''
[

134
{"score": 40},
{"score": 80}
]
''';

var scores = jsonDecode(jsonString);


assert(scores is List);

var firstScore = scores[0];


assert(firstScore is Map);
assert(firstScore['score'] == 40);

Encode a supported Dart object into a JSON-formatted string


with jsonEncode():

var scores = [
{'score': 40},
{'score': 80},
{'score': 100, 'overtime': true, 'special_guest': null}
];

var jsonText = jsonEncode(scores);


assert(jsonText ==
'[{"score":40},{"score":80},'
'{"score":100,"overtime":true,'
'"special_guest":null}]');

Only objects of type int, double, String, bool, null, List, or Map (with string
keys) are directly encodable into JSON. List and Map objects are encoded
recursively.

You have two options for encoding objects that aren’t directly encodable. The
first is to invoke encode() with a second argument: a function that returns an
object that is directly encodable. Your second option is to omit the second
argument, in which case the encoder calls the object’s toJson() method.

For more examples and links to JSON-related packages, see JSON Support.

Decoding and encoding UTF-8


characters
Use utf8.decode() to decode UTF8-encoded bytes to a Dart string:

List<int> utf8Bytes = [
0xc3, 0x8e, 0xc3, 0xb1, 0xc5, 0xa3, 0xc3, 0xa9,

135
0x72, 0xc3, 0xb1, 0xc3, 0xa5, 0xc5, 0xa3, 0xc3,
0xae, 0xc3, 0xb6, 0xc3, 0xb1, 0xc3, 0xa5, 0xc4,
0xbc, 0xc3, 0xae, 0xc5, 0xbe, 0xc3, 0xa5, 0xc5,
0xa3, 0xc3, 0xae, 0xe1, 0xbb, 0x9d, 0xc3, 0xb1
];

var funnyWord = utf8.decode(utf8Bytes);

assert(funnyWord == 'Îñţérñåţîöñåļîžåţîờñ');

To convert a stream of UTF-8 characters into a Dart string,


specify utf8.decoder to the Stream transform() method:

var lines =

utf8.decoder.bind(inputStream).transform(LineSplitter());
try {
await for (var line in lines) {
print('Got ${line.length} characters from stream');
}
print('file is now closed');
} catch (e) {
print(e);
}

Use utf8.encode() to encode a Dart string as a list of UTF8-encoded bytes:

List<int> encoded = utf8.encode('Îñţérñåţîöñåļîžåţîờñ');

assert(encoded.length == utf8Bytes.length);
for (int i = 0; i < encoded.length; i++) {
assert(encoded[i] == utf8Bytes[i]);
}

Other functionality
The dart:convert library also has converters for ASCII and ISO-8859-1
(Latin1). For details, see the API reference for the dart:convert library.

dart:html - browser-based apps


Use the dart:html library to program the browser, manipulate objects and
elements in the DOM, and access HTML5 APIs. DOM stands for Document
Object Model, which describes the hierarchy of an HTML page.

136
Other common uses of dart:html are manipulating styles (CSS), getting data
using HTTP requests, and exchanging data usingWebSockets. HTML5 (and
dart:html) has many additional APIs that this section doesn’t cover. Only web
apps can use dart:html, not command-line apps.

Note: For a higher level approach to web app UIs, use a web framework such
as AngularDart.

To use the HTML library in your web app, import dart:html:

import 'dart:html';

Manipulating the DOM


To use the DOM, you need to know about windows, documents, elements,
and nodes.

A Window object represents the actual window of the web browser. Each
Window has a Document object, which points to the document that’s currently
loaded. The Window object also has accessors to various APIs such as
IndexedDB (for storing data), requestAnimationFrame (for animations), and
more. In tabbed browsers, each tab has its own Window object.

With the Document object, you can create and manipulate Element objects
within the document. Note that the document itself is an element and can be
manipulated.

The DOM models a tree of Nodes. These nodes are often elements, but they
can also be attributes, text, comments, and other DOM types. Except for the
root node, which has no parent, each node in the DOM has one parent and
might have many children.

Finding elements
To manipulate an element, you first need an object that represents it. You can
get this object using a query.

Find one or more elements using the top-level


functions querySelector() and querySelectorAll(). You can query by ID, class,
tag, name, or any combination of these. The CSS Selector Specification
guide defines the formats of the selectors such as using a # prefix to specify
IDs and a period (.) for classes.

The querySelector() function returns the first element that matches the
selector, while querySelectorAll()returns a collection of elements that match
the selector.

137
// Find an element by id (an-id).
Element elem1 = querySelector('#an-id');

// Find an element by class (a-class).


Element elem2 = querySelector('.a-class');

// Find all elements by tag (<div>).


List<Element> elems1 = querySelectorAll('div');

// Find all text inputs.


List<Element> elems2 = querySelectorAll(
'input[type="text"]',
);

// Find all elements with the CSS class 'class'


// inside of a <p> that is inside an element with
// the ID 'id'.
List<Element> elems3 = querySelectorAll('#id p.class');

Manipulating elements
You can use properties to change the state of an element. Node and its
subtype Element define the properties that all elements have. For example, all
elements have classes, hidden, id, style, and title properties that you can use
to set state. Subclasses of Element define additional properties, such as
the href property of AnchorElement.

Consider this example of specifying an anchor element in HTML:

<a id="example" href="http://example.com">link text</a>

This <a> tag specifies an element with an href attribute and a text node
(accessible via a text property) that contains the string “linktext”. To change
the URL that the link goes to, you can use AnchorElement’s href property:

var anchor = querySelector('#example') as AnchorElement;


anchor.href = 'http://dartlang.org';

Often you need to set properties on multiple elements. For example, the
following code sets the hidden property of all elements that have a class of
“mac”, “win”, or “linux”. Setting the hidden property to true has the same effect
as adding display:none to the CSS.

<!-- In HTML: -->


<p>
<span class="linux">Words for Linux</span>
<span class="macos">Words for Mac</span>
138
<span class="windows">Words for Windows</span>
</p>
// In Dart:
final osList = ['macos', 'windows', 'linux'];
final userOs = determineUserOs();

// For each possible OS...


for (var os in osList) {
// Matches user OS?
bool shouldShow = (os == userOs);

// Find all elements with class=os. For example, if


// os == 'windows', call querySelectorAll('.windows')
// to find all elements with the class "windows".
// Note that '.$os' uses string interpolation.
for (var elem in querySelectorAll('.$os')) {
elem.hidden = !shouldShow; // Show or hide.
}
}

When the right property isn’t available or convenient, you can use
Element’s attributes property. This property is a Map<String, String>, where
the keys are attribute names. For a list of attribute names and their meanings,
see the MDN Attributes page. Here’s an example of setting an attribute’s
value:

elem.attributes['someAttribute'] = 'someValue';

Creating elements
You can add to existing HTML pages by creating new elements and attaching
them to the DOM. Here’s an example of creating a paragraph (<p>) element:

var elem = ParagraphElement();


elem.text = 'Creating is easy!';

You can also create an element by parsing HTML text. Any child elements are
also parsed and created.

var elem2 = Element.html(


'<p>Creating <em>is</em> easy!</p>',
);

Note that elem2 is a ParagraphElement in the preceding example.

Attach the newly created element to the document by assigning a parent to the
element. You can add an element to any existing element’s children. In the
139
following example, body is an element, and its child elements are accessible
(as a List<Element>) from the children property.

document.body.children.add(elem2);

Adding, replacing, and removing nodes


Recall that elements are just a kind of node. You can find all the children of a
node using the nodes property of Node, which returns a List<Node> (as
opposed to children, which omits non-Element nodes). Once you have this list,
you can use the usual List methods and operators to manipulate the children
of the node.

To add a node as the last child of its parent, use the List add() method:

querySelector('#inputs').nodes.add(elem);

To replace a node, use the Node replaceWith() method:

querySelector('#status').replaceWith(elem);

To remove a node, use the Node remove() method:

// Find a node by ID, and remove it from the DOM.


querySelector('#expendable').remove();

Manipulating CSS styles


CSS, or cascading style sheets, defines the presentation styles of DOM
elements. You can change the appearance of an element by attaching ID and
class attributes to it.

Each element has a classes field, which is a list. Add and remove CSS classes
simply by adding and removing strings from this collection. For example, the
following sample adds the warning class to an element:

var elem = querySelector('#message');


elem.classes.add('warning');

It’s often very efficient to find an element by ID. You can dynamically set an
element ID with the id property:

var message = DivElement();


message.id = 'message2';
message.text = 'Please subscribe to the Dart mailing
list.';

140
You can reduce the redundant text in this example by using method cascades:

var message = DivElement()


..id = 'message2'
..text = 'Please subscribe to the Dart mailing list.';

While using IDs and classes to associate an element with a set of styles is
best practice, sometimes you want to attach a specific style directly to the
element:

message.style
..fontWeight = 'bold'
..fontSize = '3em';

Handling events
To respond to external events such as clicks, changes of focus, and
selections, add an event listener. You can add an event listener to any
element on the page. Event dispatch and propagation is a complicated
subject; research the details if you’re new to web programming.

Add an event handler using element.onEvent.listen(function), where Event is


the event name and function is the event handler.

For example, here’s how you can handle clicks on a button:

// Find a button by ID and add an event handler.


querySelector('#submitInfo').onClick.listen((e) {
// When the button is clicked, it runs this code.
submitData();
});

Events can propagate up and down through the DOM tree. To discover which
element originally fired the event, use e.target:

document.body.onClick.listen((e) {
final clickedElem = e.target;
// ...
});

To see all the events for which you can register an event listener, look for
“onEventType” properties in the API docs for Element and its subclasses.
Some common events include:

 change
 blur
 keyDown
141
 keyUp
 mouseDown
 mouseUp

Using HTTP resources with


HttpRequest
Formerly known as XMLHttpRequest, the HttpRequest class gives you access
to HTTP resources from within your browser-based app. Traditionally, AJAX-
style apps make heavy use of HttpRequest. Use HttpRequest to dynamically
load JSON data or any other resource from a web server. You can also
dynamically send data to a web server.

Getting data from the server


The HttpRequest static method getString() is an easy way to get data from a
web server. Use await with the getString() call to ensure that you have the
data before continuing execution.

Future main() async {


String pageHtml = [!await
HttpRequest.getString(url);!]
// Do something with pageHtml...
}

Use try-catch to specify an error handler:

try {
var data = await HttpRequest.getString(jsonUri);
// Process data...
} catch (e) {
// Handle exception...
}

If you need access to the HttpRequest, not just the text data it retrieves, you
can use the request() static method instead ofgetString(). Here’s an example
of reading XML data:

Future main() async {


HttpRequest req = await HttpRequest.request(
url,
method: 'HEAD',
);
if (req.status == 200) {

142
// Successful URL access...
}
// ···
}

You can also use the full API to handle more interesting cases. For example,
you can set arbitrary headers.

The general flow for using the full API of HttpRequest is as follows:

1. Create the HttpRequest object.


2. Open the URL with either GET or POST.
3. Attach event handlers.
4. Send the request.

For example:

var request = HttpRequest();


request
..open('POST', url)
..onLoadEnd.listen((e) => requestComplete(request))
..send(encodedData);

Sending data to the server


HttpRequest can send data to the server using the HTTP method POST. For
example, you might want to dynamically submit data to a form handler.
Sending JSON data to a RESTful web service is another common example.

Submitting data to a form handler requires you to provide name-value pairs as


URI-encoded strings. (Information about the URI class is in the URIs section of
the Dart Library Tour.) You must also set the Content-type header
to application/x-www-form-urlencode if you wish to send data to a form handler.

String encodeMap(Map data) => data.keys


.map((k) =>
'${Uri.encodeComponent(k)}=${Uri.encodeComponent(data[k])}
')
.join('&');

Future main() async {


var data = {'dart': 'fun', 'angular': 'productive'};

var request = HttpRequest();


request
..open('POST', url)
..setRequestHeader(

143
'Content-type',
'application/x-www-form-urlencoded',
)
..send(encodeMap(data));

await request.onLoadEnd.first;

if (request.status == 200) {
// Successful URL access...
}
// ···
}

Sending and receiving real-time data


with WebSockets
A WebSocket allows your web app to exchange data with a server
interactively—no polling necessary. A server creates the WebSocket and
listens for requests on a URL that starts with ws://—for example,
ws://127.0.0.1:1337/ws. The data transmitted over a WebSocket can be a
string or a blob. Often, the data is a JSON-formatted string.

To use a WebSocket in your web app, first create a WebSocket object,


passing the WebSocket URL as an argument:

var ws = WebSocket('ws://echo.websocket.org');

Sending data
To send string data on the WebSocket, use the send() method:

ws.send('Hello from Dart!');

Receiving data
To receive data on the WebSocket, register a listener for message events:

ws.onMessage.listen((MessageEvent e) {
print('Received message: ${e.data}');
});

The message event handler receives a MessageEvent object. This


object’s data field has the data from the server.

Handling WebSocket events


144
Your app can handle the following WebSocket events: open, close, error, and
(as shown earlier) message. Here’s an example of a method that creates a
WebSocket object and registers handlers for open, close, error, and message
events:

void initWebSocket([int retrySeconds = 1]) {


var reconnectScheduled = false;

print("Connecting to websocket");

void scheduleReconnect() {
if (!reconnectScheduled) {
Timer(Duration(seconds: retrySeconds),
() => initWebSocket(retrySeconds * 2));
}
reconnectScheduled = true;
}

ws.onOpen.listen((e) {
print('Connected');
ws.send('Hello from Dart!');
});

ws.onClose.listen((e) {
print('Websocket closed, retrying in ' +
'$retrySeconds seconds');
scheduleReconnect();
});

ws.onError.listen((e) {
print("Error connecting to ws");
scheduleReconnect();
});

ws.onMessage.listen((MessageEvent e) {
print('Received message: ${e.data}');
});
}

Plus d'information
This section barely scratched the surface of using the dart:html library. For
more information, see the documentation for dart:html. Dart has additional
libraries for more specialized web APIs, such as web
audio, IndexedDB, and WebGL.

For more information about Dart web libraries, see the web library overview.
145
dart:io - I/O for servers and
command-line apps
The dart:io library provides APIs to deal with files, directories, processes,
sockets, WebSockets, and HTTP clients and servers.

Important: Only Flutter mobile apps, command-line scripts, and servers can
import and use dart:io, not web apps.

In general, the dart:io library implements and promotes an asynchronous API.


Synchronous methods can easily block an application, making it difficult to
scale. Therefore, most operations return results via Future or Stream objects,
a pattern common with modern server platforms such as Node.js.

The few synchronous methods in the dart:io library are clearly marked with a
Sync suffix on the method name. Synchronous methods aren’t covered here.

To use the dart:io library you must import it:

import 'dart:io';

Files and directories


The I/O library enables command-line apps to read and write files and browse
directories. You have two choices for reading the contents of a file: all at once,
or streaming. Reading a file all at once requires enough memory to store all
the contents of the file. If the file is very large or you want to process it while
reading it, you should use a Stream, as described in Streaming file contents.

Reading a file as text


When reading a text file encoded using UTF-8, you can read the entire file
contents with readAsString(). When the individual lines are important, you can
use readAsLines(). In both cases, a Future object is returned that provides the
contents of the file as one or more strings.

Future main() async {


var config = File('config.txt');
var contents;

// Put the whole file in a single string.


contents = await config.readAsString();

146
print('The file is ${contents.length} characters
long.');

// Put each line of the file into its own string.


contents = await config.readAsLines();
print('The file is ${contents.length} lines long.');
}

Reading a file as binary


The following code reads an entire file as bytes into a list of ints. The call
to readAsBytes() returns a Future, which provides the result when it’s available.

Future main() async {


var config = File('config.txt');

var contents = await config.readAsBytes();


print('The file is ${contents.length} bytes long.');
}

Handling errors
To capture errors so they don’t result in uncaught exceptions, you can register
a catchError handler on the Future, or (in an async function) use try-catch:

Future main() async {


var config = File('config.txt');
try {
var contents = await config.readAsString();
print(contents);
} catch (e) {
print(e);
}
}

Streaming file contents


Use a Stream to read a file, a little at a time. You can use either the Stream
API or await for, part of Dart’s asynchrony support.

import 'dart:io';
import 'dart:convert';

Future main() async {


var config = File('config.txt');
Stream<List<int>> inputStream = config.openRead();

147
var lines =

utf8.decoder.bind(inputStream).transform(LineSplitter());
try {
await for (var line in lines) {
print('Got ${line.length} characters from stream');
}
print('file is now closed');
} catch (e) {
print(e);
}
}

Writing file contents


You can use an IOSink to write data to a file. Use the File openWrite() method
to get an IOSink that you can write to. The default mode, FileMode.write,
completely overwrites existing data in the file.

var logFile = File('log.txt');


var sink = logFile.openWrite();
sink.write('FILE ACCESSED ${DateTime.now()}\n');
await sink.flush();
await sink.close();

To add to the end of the file, use the optional mode parameter to
specify FileMode.append:

var sink = logFile.openWrite(mode: FileMode.append);

To write binary data, use add(List<int> data).

Listing files in a directory


Finding all files and subdirectories for a directory is an asynchronous
operation. The list() method returns a Stream that emits an object when a file
or directory is encountered.

Future main() async {


var dir = Directory('tmp');

try {
var dirList = dir.list();
await for (FileSystemEntity f in dirList) {
if (f is File) {
print('Found file ${f.path}');

148
} else if (f is Directory) {
print('Found dir ${f.path}');
}
}
} catch (e) {
print(e.toString());
}
}

Other common functionality


The File and Directory classes contain other functionality, including but not
limited to:

 Creating a file or directory: create() in File and Directory


 Deleting a file or directory: delete() in File and Directory
 Getting the length of a file: length() in File
 Getting random access to a file: open() in File

Refer to the API docs for File and Directory for a full list of methods.

HTTP clients and servers


The dart:io library provides classes that command-line apps can use for
accessing HTTP resources, as well as running HTTP servers.

HTTP server
The HttpServer class provides the low-level functionality for building web
servers. You can match request handlers, set headers, stream data, and
more.

The following sample web server returns simple text information. This server
listens on port 8888 and address 127.0.0.1 (localhost), responding to requests
for the path /dart. For any other path, the response is status code 404 (page
not found).

Future main() async {


final requests = await HttpServer.bind('localhost',
8888);
await for (var request in requests) {
processRequest(request);
}
}

149
void processRequest(HttpRequest request) {
print('Got request for ${request.uri.path}');
final response = request.response;
if (request.uri.path == '/dart') {
response
..headers.contentType = ContentType(
'text',
'plain',
)
..write('Hello from the server');
} else {
response.statusCode = HttpStatus.notFound;
}
response.close();
}

HTTP client
The HttpClient class helps you connect to HTTP resources from your Dart
command-line or server-side application. You can set headers, use HTTP
methods, and read and write data. The HttpClient class does not work in
browser-based apps. When programming in the browser, use the dart:html
HttpRequest class. Here’s an example of using HttpClient:

Future main() async {


var url = Uri.parse('http://localhost:8888/dart');
var httpClient = HttpClient();
var request = await httpClient.getUrl(url);
var response = await request.close();
var data = await utf8.decoder.bind(response).toList();
print('Response ${response.statusCode}: $data');
httpClient.close();
}

Plus d'information
This page showed how to use the major features of the dart:io library. Besides
the APIs discussed in this section, the dart:io library also provides APIs
for processes, sockets, and web sockets. For more information about server-
side and command-line app development, see the server-side Dart overview.

For information on other dart:* libraries, see the library tour.

150
Summary
This page introduced you to the most commonly used functionality in Dart’s
built-in libraries. It didn’t cover all the built-in libraries, however. Others that
you might want to look into include dart:collection and dart:typed_data, as well
as platform-specific libaries like theDart web development libraries and
the Flutter libraries.

You can get yet more libraries by using the pub package manager.
The collection, crypto, http, intl, and test libraries are just a sampling of what
you can install using pub.

To learn more about the Dart language, see the Visite du langage.

151

Вам также может понравиться