Flutter Series Four - Introduction au langage Dart

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

  1. 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 vardé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.

  2. dynamiqueObjet

    ObjectIl s'agit de la classe de base racine de tous les objets de dart, ce qui signifie que tous les types sont des Objectsous - classes (y compris Function et Null), de sorte que tout type de données peut être affecté à l' Objectobjet déclaré. dynamicIdentique aux varmots-clés, et les variables déclarées peuvent être affectées à n'importe quel objet.et dynamicles Objectsimilitudes 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;
    

    dynamicLa Objectdifférence est que le dynamiccompilateur d'objets déclarés fournira toutes les combinaisons possibles et que l' Objectobjet 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 dynamicde cette fonctionnalité et Objective-Cdu idrôle du genre. dynamicCette fonctionnalité nous permet de l'utiliser avec une attention particulière, il est très facile d'introduire une erreur d'exécution.

  1. final et const

    Si vous n'avez jamais l'intention de modifier une variable, utilisez finalou constnon var, et ce n'est pas non plus un type. Une finalvariable ne peut être définie qu'une seule fois, c'est la différence entre les deux: constla variable est une constante de compilation, finalvariable utilisée lors de sa première initialisation. Pour les variables qui sont modifiées finalou constmodifié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.

  1. 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 dynamictraité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);
    
  2. 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 ;
    
  3. Fonctionne comme une variable

    var say= (str){
      print(str);
    };
    say("hi world");
    
  4. Fonction passée en paramètre

    void execute(var callback){
        callback();
    }
    execute(()=>print("xxx"))
    
  5. 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
    
  6. 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 Futureou d' Streamobjet. 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.

asyncEt les awaitmots-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

FutureIl est Promisetrè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 Futurela valeur de retour de toutes les API est toujours un Futureobjet, elle peut donc être facilement chaînée.

Avenir, alors

Pour faciliter l'exemple, dans cet exemple, nous avons Future.delayedcréé 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 thenle 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 catchErrorattraper 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 thenfonction de rappel ne sera pas exécutée et remplacée par catchErrorla fonction de rappel sera appelée; cependant, non seulement le catchErrorrappel pour attraper l'erreur, thenla 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 thenou respectivement catch. La seconde consiste à utiliser Futurele whenCompleterappel. 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.waitqu'il accepte un Futuretableau de paramètres. Le rappel de réussite Futurene sera déclenché qu'une fois que tous les tableaux auront été exécutés avec succès then. Tant qu'une Futureexécution échoue, le rappel d'erreur sera déclenché. Ensuite, nous utilisons la simulation Future.delayedpour 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/awaitLes async/awaitfonctions et l'utilisation de Dart et de JavaScript sont exactement les mêmes. Si vous connaissez déjà async/awaitl'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.thenrappel 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/awaitmême changer de nom. Ensuite, regardons l'adoption Futureet async/awaitcomment é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, " FutureLa valeur de retour de toutes les API est toujours un Futureobjet, elle peut donc être facilement chaînée." S'il y en a une renvoyée Future, elle futuresera exécutée et ce qui suit sera déclenché après l'exécution des thenrappels, dans cet ordre vers le bas, évitez les couches de nidification.

Utilisez async / await pour éliminer l'enfer des rappels

En Futurerappelant Futurela 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);   
   }  
}
  • asyncUtilisé pour indiquer que la fonction est asynchrone, la fonction définie renvoie un Futureobjet, vous pouvez utiliser la méthode then pour ajouter une fonction de rappel.
  • awaitSuivi par une Futureattente d'affichage de la fin de la tâche asynchrone, l'achèvement asynchrone s'arrêtera; awaitdoit apparaître asyncdans la fonction.

Comme vous pouvez le voir, nous avons async/awaitreprésenté un flux asynchrone avec du code synchrone.

En fait, que ce soit en JavaScript ou Dart, il ne async/awaits'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

StreamIl est également utilisé pour recevoir des données d'événement asynchrones, et la Futurediffé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. StreamIl 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!

 

 

 

Je suppose que tu aimes

Origine blog.csdn.net/MYBOYER/article/details/89676545
conseillé
Classement