Concept important
Lorsque vous apprenez le langage Dart, n'oubliez pas les faits et concepts suivants:
- Tout ce qui peut être placé dans une variable est un objet , et chaque objet est une instance d'une classe . Les nombres, les fonctions et les valeurs nulles sont des objets. Tous les objets héritent de la classe [Object].
- Bien que Dart soit fortement typé, la déclaration de type est facultative car Dart peut déduire le type. Si vous voulez préciser qu'aucun type n'est requis, utilisez [type spécial dynamique].
- Dart prend en charge les types courants, tels que List <int> (liste d'entiers) ou List <dynamic> (liste d'objets de tout type).
- Dart prend en charge les fonctions de niveau supérieur (telles que main ()) et les fonctions liées à des classes ou des objets (méthodes statiques et d'instance, respectivement). Vous pouvez également créer des fonctions dans des fonctions (fonctions imbriquées ou locales).
- De même, Dart prend en charge les variables de niveau supérieur, ainsi que les variables liées à des classes ou des objets (variables statiques et d'instance). Les variables d'instance sont parfois appelées champs ou attributs.
- Contrairement à Java, Dart n'a pas de mots clés publics, protégés et privés. Si l'identificateur commence par un trait de soulignement (_), l'identificateur est privé pour sa bibliothèque. Pour plus de détails, voir [Bibliothèque et visibilité].
- Les identificateurs peuvent commencer par une lettre ou un trait de soulignement (_), puis par n'importe quelle combinaison de ces caractères et chiffres.
- Parfois, que quelque chose soit une expression ou une déclaration est très important, ces deux mots doivent donc être exacts.
- Les outils Dart peuvent signaler deux types de problèmes: les avertissements et les erreurs. Les avertissements indiquent simplement que votre code peut ne pas fonctionner, mais ils n'empêcheront pas votre programme de s'exécuter. L'erreur peut être une erreur de compilation ou une erreur d'exécution. Les erreurs de compilation empêchent l'exécution du code; les erreurs d'exécution provoquent des exceptions lorsque le code est exécuté.
L'objectif de conception de Dart devrait être de comparer Java et JavaScript. Dart est très similaire à Java en termes de syntaxe statique, comme les définitions de type, les déclarations de fonctions, les génériques, etc., et est très similaire à JavaScript en termes de fonctionnalités dynamiques , telles que les fonctions. Fonctions de style, prise en charge asynchrone, etc. En plus d'intégrer les atouts des langages Java et JavaScript, Dart possède également d'autres syntaxes expressives, telles que des paramètres nommés facultatifs, ..
(opérateur en cascade) et ?.
(opérateur d'accès aux membres conditionnels) et ??
(opérateur d'assignation nulle)). En fait, les lecteurs qui en savent plus sur les langages de programmation constateront que Dart voit non seulement les ombres de Java et de JavaScript, mais également d'autres langages de programmation. Par exemple, les paramètres nommés sont utilisés depuis longtemps dans Objective-C et Swift. est très courant, et l' ??
opérateur existe déjà dans la syntaxe Php 7.0, nous pouvons donc voir que Google a de grands espoirs pour le langage Dart, et il veut intégrer Dart dans un langage de programmation avec le meilleur de centaines de familles.
Ensuite, nous donnons d'abord une brève introduction à la syntaxe de Dart, puis nous faisons une brève comparaison entre Dart et JavaScript et Java pour faciliter une meilleure compréhension des lecteurs.
Remarque: cet article présentera principalement les fonctionnalités grammaticales couramment utilisées dans le développement de Flutter. Si vous souhaitez en savoir plus sur Dart, les lecteurs peuvent consulter le site Web officiel de Dart pour en savoir plus. Il existe désormais de nombreux documents relatifs à Dart sur Internet. De plus, Dart 2.0 a été officiellement publié et tous les exemples ici utilisent la syntaxe Dart 2.0.
Déclaration de variable
-
où
Semblable à JavaScript
var
, il peut recevoir n'importe quel type de variable, mais la plus grande différence est qu'une fois que la variable var dans Dart est affectée, le type sera déterminé et vous ne pouvez pas changer son type, tel que:var t; t="hi world"; // 下面代码在dart中会报错,因为变量t的类型已经确定为String, // 类型一旦确定后则不能再更改其类型。 t=1000;
Le code ci-dessus ne pose aucun problème en JavaScript. Les développeurs frontaux doivent faire attention. La raison de cette différence est que Dart lui-même est un langage fortement typé. Toute variable a un certain type. Dans Dart, lorsque vous
var
déclarez une variable plus tard, Dart inférera son type en fonction du type des premières données d'affectation lors de la compilation, et son type a été déterminé après l'achèvement de la compilation, et JavaScript est un langage de script purement faiblement typé, et var est juste un moyen de déclarer des variables. -
dynamique和Objet
Object
Il s'agit de la classe de base racine de tous les objets de dart, ce qui signifie que tous les types sont desObject
sous - classes (y compris Function et Null), de sorte que tout type de données peut être affecté à l'Object
objet déclaré.dynamic
Identique auxvar
mots-clés, et les variables déclarées peuvent être affectées à n'importe quel objet.etdynamic
lesObject
similitudes avec lesquelles ils déclarent une variable du type d'affectation peuvent être modifiés ultérieurement.dynamic t; Object x; t = "hi world"; x = 'Hello Object'; //下面代码没有问题 t = 1000; x = 1000;
dynamic
LaObject
différence est que ledynamic
compilateur d'objets déclarés fournira toutes les combinaisons possibles et que l'Object
objet déclaré ne pourra utiliser que les propriétés et les méthodes d'Object, sinon le compilateur signalera une erreur. Par exemple:dynamic a; Object b; main() { a = ""; b = ""; printLengths(); } printLengths() { // no warning print(a.length); // warning: // The getter 'length' is not defined for the class 'Object' print(b.length); }
N'ayant pas de variable, le compilateur de la variable b se plaindra
dynamic
de cette fonctionnalité etObjective-C
duid
rôle du genre.dynamic
Cette fonctionnalité nous permet de l'utiliser avec une attention particulière, il est très facile d'introduire une erreur d'exécution.
-
final et const
Si vous n'avez jamais l'intention de modifier une variable, utilisez
final
ouconst
nonvar
, et ce n'est pas non plus un type. Unefinal
variable ne peut être définie qu'une seule fois, c'est la différence entre les deux:const
la variable est une constante de compilation,final
variable utilisée lors de sa première initialisation. Pour les variables qui sont modifiéesfinal
ouconst
modifiées, le type de variable peut être omis, tel que://可以省略String这个类型声明 final str = "hi world"; //final String str = "hi world"; const str1 = "hi world"; //const String str1 = "hi world";
fonction
Dart est un véritable langage orienté objet, donc même les fonctions sont des objets et ont un type Function . Cela signifie que les fonctions peuvent être affectées à des variables ou transmises en tant que paramètres à d'autres fonctions, ce qui est une caractéristique typique de la programmation fonctionnelle.
-
Déclaration de fonction
bool isNoble(int atomicNumber) { return _nobleGases[atomicNumber] != null; }
Si la déclaration de la fonction dart ne déclare pas explicitement le type de valeur de retour, elle sera
dynamic
traitée par défaut . Notez que la valeur de retour de la fonction n'a pas d'inférence de type:typedef bool CALLBACK(); //不指定返回类型,此时默认为dynamic,不是bool isNoble(int atomicNumber) { return _nobleGases[atomicNumber] != null; } void test(CALLBACK cb){ print(cb()); } //报错,isNoble不是bool类型 test(isNoble);
-
Pour les fonctions qui ne contiennent qu'une seule expression, vous pouvez utiliser la syntaxe abrégée
bool isNoble (int atomicNumber )=> _nobleGases [ atomicNumber ] != null ;
-
Fonctionne comme une variable
var say= (str){ print(str); }; say("hi world");
-
Fonction passée en paramètre
void execute(var callback){ callback(); } execute(()=>print("xxx"))
-
Paramètres de position facultatifs
Enveloppez un ensemble de paramètres de fonction, marqués par [] comme paramètres de position 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 paramètres facultatifs:
say('Bob', 'Howdy'); //结果是: Bob says Howdy
Voici un exemple d'appel de cette fonction avec le troisième paramètre:
say('Bob', 'Howdy', 'smoke signal'); //结果是:Bob says Howdy with a smoke signal
-
Paramètres nommés facultatifs
Lors de la définition d'une fonction, utilisez {param1, param2,…} pour spécifier les paramètres nommés. Par exemple:
//设置[bold]和[hidden]标志 void enableFlags({bool bold, bool hidden}) { // ... }
Lors de l'appel d'une fonction, vous pouvez utiliser des paramètres nommés désignés. Par exemple:
paramName: value
enableFlags(bold: true, hidden: false);
Les paramètres nommés facultatifs sont beaucoup utilisés dans Flutter.
Prise en charge asynchrone
La bibliothèque Dart a beaucoup de fonctions de retour Future
ou d' Stream
objet. Ces fonctions sont appelées fonctions asynchrones : elles ne reviendront qu'après la configuration de certaines opérations chronophages, telles que les opérations d'E / S. Au lieu d'attendre la fin de cette opération.
async
Et les await
mots-clés prennent en charge la programmation asynchrone et exécutent du code asynchrone que vous écrivez qui est très similaire au code synchrone.
Avenir
Future
Il est Promise
très similaire à JavaScript , qui représente l'achèvement final (ou l'échec) d'une opération asynchrone et sa valeur de résultat. En termes simples, il est utilisé pour traiter des opérations asynchrones. Si le processus asynchrone réussit, l'opération réussie est exécutée et si le processus asynchrone échoue, l'erreur est capturée ou l'opération suivante est arrêtée. Un futur ne correspondra qu'à un seul résultat, succès ou échec.
En raison de ses nombreuses fonctions, nous ne présentons ici que ses API et fonctionnalités couramment utilisées. N'oubliez pas non plus que Future
la valeur de retour de toutes les API est toujours un Future
objet, elle peut donc être facilement chaînée.
Avenir, alors
Pour faciliter l'exemple, dans cet exemple, nous avons Future.delayed
créé une tâche retardée (le scénario réel sera une tâche chronophage, telle qu'une requête réseau), c'est-à-dire que la chaîne de résultat "hi world!" Est renvoyée après 2 secondes, puis nous recevons then
le résultat de l'asynchrone et imprimons les résultats, comme suit:
Future.delayed(new Duration(seconds: 2),(){
return "hi world!";
}).then((data){
print(data);
});
Future.catchError
Si une erreur se produit dans la tâche asynchrone, nous pouvons catchError
attraper l'erreur dans, nous changeons l'exemple ci-dessus en:
Future.delayed(new Duration(seconds: 2),(){
//return "hi world!";
throw AssertionError("Error");
}).then((data){
//执行成功会走到这里
print("success");
}).catchError((e){
//执行失败会走到这里
print(e);
});
Dans cet exemple, nous lançons une exception dans les tâches asynchrones, la then
fonction de rappel ne sera pas exécutée et remplacée par catchError
la fonction de rappel sera appelée; cependant, non seulement le catchError
rappel pour attraper l'erreur, then
la méthode ainsi que des paramètres facultatifs onError
, nous pouvons utilisez-le également pour intercepter les exceptions:
Future.delayed(new Duration(seconds: 2), () {
//return "hi world!";
throw AssertionError("Error");
}).then((data) {
print("success");
}, onError: (e) {
print(e);
});
Future.whenComplete
Parfois, nous rencontrerons des scénarios dans lesquels quelque chose doit être fait indépendamment du succès ou de l'échec de l'exécution de la tâche asynchrone, comme ouvrir une boîte de dialogue de chargement avant la demande réseau et fermer la boîte de dialogue une fois la demande terminée. Dans ce scénario, il existe deux méthodes. La première consiste à fermer la boîte de dialogue dans then
ou respectivement catch
. La seconde consiste à utiliser Future
le whenComplete
rappel. Modifions l'exemple ci-dessus:
Future.delayed(new Duration(seconds: 2),(){
//return "hi world!";
throw AssertionError("Error");
}).then((data){
//执行成功会走到这里
print(data);
}).catchError((e){
//执行失败会走到这里
print(e);
}).whenComplete((){
//无论成功或失败都会走到这里
});
Future.wait
Parfois, nous devons attendre la fin de plusieurs tâches asynchrones avant d'effectuer certaines opérations. Par exemple, si nous avons une interface, nous devons obtenir des données à partir de deux interfaces réseau. Une fois l'acquisition réussie, nous devons effectuer des opérations spécifiques sur le deux données d'interface. Que dois-je faire si elles sont affichées sur l'interface de l'interface utilisateur après le traitement? La réponse est Future.wait
qu'il accepte un Future
tableau de paramètres. Le rappel de réussite Future
ne sera déclenché qu'une fois que tous les tableaux auront été exécutés avec succès then
. Tant qu'une Future
exécution échoue, le rappel d'erreur sera déclenché. Ensuite, nous utilisons la simulation Future.delayed
pour simuler deux tâches asynchrones pour l'acquisition de données. Lorsque les deux tâches asynchrones sont exécutées avec succès, les résultats des deux tâches asynchrones sont épissés et imprimés. Le code est le suivant:
Future.wait([
// 2秒后返回结果
Future.delayed(new Duration(seconds: 2), () {
return "hello";
}),
// 4秒后返回结果
Future.delayed(new Duration(seconds: 4), () {
return " world";
})
]).then((results){
print(results[0]+results[1]);
}).catchError((e){
print(e);
});
Après avoir exécuté le code ci-dessus, vous verrez "hello world" dans la console après 4 secondes.
Asynchroniser / attendre
async/await
Les async/await
fonctions et l'utilisation de Dart et de JavaScript sont exactement les mêmes. Si vous connaissez déjà async/await
l'utilisation de JavaScript , vous pouvez ignorer cette section directement.
L'enfer des rappels
S'il y a beaucoup de logique asynchrone dans le code et qu'un grand nombre de tâches asynchrones dépendent des résultats d'autres tâches asynchrones, il y aura inévitablement un Future.then
rappel dans la situation de rappel. Par exemple, il existe un scénario de demande où l'utilisateur se connecte pour la première fois, et une fois la connexion réussie, l'ID utilisateur est obtenu, puis l'ID utilisateur est utilisé pour demander les informations personnelles de l'utilisateur. Après avoir obtenu les informations personnelles de l'utilisateur informations, nous devons l'utiliser pour plus de commodité. En cache dans le système de fichiers local, le code est le suivant:
//先分别定义各个异步任务
Future<String> login(String userName, String pwd){
...
//用户登录
};
Future<String> getUserInfo(String id){
...
//获取用户信息
};
Future saveUserInfo(String userInfo){
...
// 保存用户信息
};
Ensuite, exécutez l'ensemble du flux de tâches:
login("alice","******").then((id){
//登录成功后通过,id获取用户信息
getUserInfo(id).then((userInfo){
//获取用户信息后保存
saveUserInfo(userInfo).then((){
//保存用户信息,接下来执行其它操作
...
});
});
})
Vous pouvez penser que s'il y a un grand nombre de dépendances asynchrones dans la logique métier, la situation ci-dessus se produira dans le rappel à l'intérieur du rappel. Trop d'imbrication entraînera une diminution de la lisibilité du code et une augmentation du taux d'erreur, et c'est Maintenance très difficile, ce problème est vivement appelé callback hell (Callback hell) . Le problème de l'enfer des rappels était très important dans JavaScript auparavant, et c'était aussi le point où JavaScript était le plus critiqué. Mais avec la publication des normes ECMAScript6 et ECMAScript7, ce problème a été très bien résolu, et les deux artefacts pour résoudre le problème callback hell sont l'introduction d'ECMAScript6 Promise
, et introduit dans ECMAScript7 async/await
. Dans Dart, les deux en JavaScript sont presque entièrement traduits: Future
équivalent Promise
, sans async/await
même changer de nom. Ensuite, regardons l'adoption Future
et async/await
comment éliminer le problème d'imbrication dans l'exemple ci-dessus.
Utilisez Future pour éliminer l'enfer des rappels
login("alice","******").then((id){
return getUserInfo(id);
}).then((userInfo){
return saveUserInfo(userInfo);
}).then((e){
//执行接下来的操作
}).catchError((e){
//错误处理
print(e);
});
Comme mentionné ci-dessus, " Future
La valeur de retour de toutes les API est toujours un Future
objet, elle peut donc être facilement chaînée." S'il y en a une renvoyée Future
, elle future
sera exécutée et ce qui suit sera déclenché après l'exécution des then
rappels, dans cet ordre vers le bas, évitez les couches de nidification.
Utilisez async / await pour éliminer l'enfer des rappels
En Future
rappelant Future
la façon d'éviter les couches imbriquées, mais toujours avec une couche de rappel, existe-t-il un moyen de nous permettre d'écrire du code de synchronisation peut être comme une manière d'effectuer des tâches asynchrones sans utiliser le rappel? La réponse est oui, il faut utiliser async/await
, regardons directement le code, puis expliquons, le code est le suivant:
task() async {
try{
String id = await login("alice","******");
String userInfo = await getUserInfo(id);
await saveUserInfo(userInfo);
//执行接下来的操作
} catch(e){
//错误处理
print(e);
}
}
async
Utilisé pour indiquer que la fonction est asynchrone, la fonction définie renvoie unFuture
objet, vous pouvez utiliser la méthode then pour ajouter une fonction de rappel.await
Suivi par uneFuture
attente d'affichage de la fin de la tâche asynchrone, l'achèvement asynchrone s'arrêtera;await
doit apparaîtreasync
dans la fonction.
Comme vous pouvez le voir, nous avons async/await
représenté un flux asynchrone avec du code synchrone.
En fait, que ce soit en JavaScript ou Dart, il ne
async/await
s'agit que d'un sucre syntaxique, et le compilateur ou l'interpréteur finira par le convertir en une chaîne d'appels Promise (Future).
Courant
Stream
Il est également utilisé pour recevoir des données d'événement asynchrones, et la Future
différence est qu'il peut recevoir les résultats (succès ou échec) de plusieurs opérations asynchrones. En d'autres termes, lors de l'exécution de tâches asynchrones, vous pouvez transmettre des données de résultat ou des exceptions d'erreur en déclenchant plusieurs événements de réussite ou d'échec. Stream
Il est souvent utilisé dans les scénarios de tâches asynchrones où les données sont lues plusieurs fois, telles que le téléchargement de contenu réseau, la lecture et l'écriture de fichiers, etc. par exemple:
Stream.fromFutures([
// 1秒后返回结果
Future.delayed(new Duration(seconds: 1), () {
return "hello 1";
}),
// 抛出一个异常
Future.delayed(new Duration(seconds: 2),(){
throw AssertionError("Error");
}),
// 3秒后返回结果
Future.delayed(new Duration(seconds: 3), () {
return "hello 3";
})
]).listen((data){
print(data);
}, onError: (e){
print(e.message);
},onDone: (){
});
Le code ci-dessus sortira à son tour:
I/flutter (17666): hello 1
I/flutter (17666): Error
I/flutter (17666): hello 3
Le code est très simple, donc je ne le répéterai pas.
Question: Puisque Stream peut recevoir plusieurs événements, pouvez-vous utiliser Stream pour implémenter un bus d'événements en mode abonné?
Pour résumer
À travers l'introduction ci-dessus, je pense que vous devriez avoir une première impression de Dart. Puisque l'auteur utilise également Java et JavaScript à des moments ordinaires, je vais parler de mes points de vue basés sur ma propre expérience et combinant Java et JavaScript.
La raison pour laquelle Dart est comparé à Java et JavaScript est qu'ils sont des représentants typiques des langages fortement typés et des langages faiblement typés respectivement, et de nombreux endroits dans la grammaire de Dart s'appuient également sur Java et JavaScript.
Dart contre Java
Objectivement parlant, Dart est en effet plus expressif que Java au niveau grammatical; au niveau de la VM, Dart VM a été optimisé à plusieurs reprises pour la récupération de la mémoire et le débit. Cependant, pour des comparaisons de performances spécifiques, l'auteur n'a pas trouvé de données de test pertinentes, mais In à mon avis, tant que le langage Dart peut être populaire, il n'y a pas lieu de s'inquiéter des performances de la VM. Après tout, Google a déjà beaucoup de technologie en marche (vm inutile mais avec GC), javascript (v8) , dalvik (java vm sur android) Accumulation. Il est à noter que Dart peut déjà atteindre GC en 10 ms dans Flutter, donc en comparant Dart et Java, le facteur décisif ne sera pas la performance. Au niveau grammatical, Dart est plus expressif que Java. Le plus important est que Dart prend en charge la programmation fonctionnelle beaucoup plus forte que Java (ne restant actuellement que dans les expressions lamda). Le vrai défaut de Dart est l' écologie , mais l'auteur je crois qu'avec la popularité progressive de Flutter, il va revenir en arrière et pousser le développement accéléré de l'écologie Dart.Pour Dart, cela prend du temps maintenant.
Dart vs JavaScript
Les types faibles de JavaScript ont été pris de court, donc TypeScript, Coffeescript et même le flux de Facebook (bien que ce ne soit pas un sur-ensemble de JavaScript, il fournit également une vérification de type statique via des outils d'annotation et de packaging). Parmi les langages de script que j'ai utilisés (j'ai utilisé Python et PHP), JavaScript est sans aucun doute le langage de script avec le meilleur support dynamique . Par exemple, en JavaScript, tout objet peut être étendu dynamiquement à tout moment. Pour ceux qui maîtrisent JavaScript Pour les maîtres, il s'agit sans aucun doute d'une épée tranchante. Cependant, tout a deux côtés. La puissante fonctionnalité dynamique de JavaScript est également une arme à double tranchant. Vous pouvez souvent entendre une autre voix, pensant que la nature dynamique de JavaScript est terrible. Trop flexible rend le code difficile à prévoir., Impossible de restreindre modifications indésirables. Après tout, certaines personnes sont toujours préoccupées par le code écrit par elles-mêmes ou par d'autres, elles veulent rendre le code contrôlable et s'attendent à ce qu'un système de vérification de type statique les aide à réduire les erreurs. Pour cette raison, dans Flutter, Dart a presque abandonné les fonctionnalités dynamiques du langage de script, telles que ne pas prendre en charge la réflexion ou créer dynamiquement des fonctions. Et Dart obligé d'ouvrir la vérification de type (mode fort) dans 2.0, le mode vérifié d'origine (mode vérifié) et le type facultatif (type facultatif) disparaîtront, donc en termes de sécurité de type, Dart et TypeScript, Coffeescript sont similaires, donc de ce point de vue, Dart n'a pas d'avantages évidents, mais lorsqu'il est combiné, Dart peut effectuer des scripts côté serveur, du développement APP et du développement Web, ce qui présente des avantages!