Dans une version récente de Dart 2.6, le langage a introduit une nouvelle fonction, une extension statique ou des méthodes d'extension statique, qui vous permet d'ajouter de nouvelles méthodes aux types existants. Pourquoi avons-nous besoin d'une extension? Comment les utiliser et à quoi servent-ils?

Présentation
Pour commencer, qu'est-ce que l'extension en général?
L'extension est un sucre syntaxique qui étend une classe existante à un endroit différent du module de déclaration de classe.
En programmation, les méthodes d'extension existent depuis longtemps, alors elles ont pu se lancer. L'extension est activement utilisée dans des langages tels que C #, Java via Manifold, Swift, Kotlin et bien d'autres.
Le problème
Disons que nous avons une méthode catchError, qui est tout simplement horrible et doit être réécrite dans une nouvelle fonction cool. Supposons qu'il utilise une fonction de tout type comme argument pour un emplacement d'une fonction strictement typée ou pour vérifier le type d'une fonction, et cela se produit car il y a 8 mois lors du développement de cette fonctionnalité, c'était logique à l'époque.
La première chose qui me vient à l'esprit est de réécrire cette fonction, mais ici nous sommes confrontés au problème qu'elle se produit trop souvent dans le projet, et la modification de la fonction entraînera l'inopérabilité de l'ensemble du projet.
Eh bien, si la première option n'est pas pour nous. adapté, pour des raisons logiques, je pourrai alors implémenter une nouvelle fonction Future qui répondra à toutes mes exigences.
abstract class Future<T> { ... /// Catches any [error] of type [E]. Future<T> onError<E>(FutureOr<T> handleError(E error, StackTrace stack)) => this.catchError(... - ...); } ... }
et je vais l'appeler comme ça:
Future<String> someString = ...; someString.onError((FormatException e, s) => ...).then(...);
Malheureusement, je ne peux pas ajouter cette fonction à la classe Future. Si je le fais, je l'ajouterai également à l'interface Future, et toute autre classe qui implémentera cette interface sera incomplète et ne compilera plus.
Eh bien, une autre option consiste à implémenter une fonction tierce qui ressemblera à ceci:
Future<T> onFutureError<T, E>(Future<T> source, FutureOr<T> handleError(E error, StackTrace stack)) => source.catchError(... - ...);
Et son appel ressemblerait à ceci:
Future<String> someString = ...; onFutureError(someString, (FormatException e, s) => ...).then(...);
Génial, tout fonctionne! Mais il est triste qu'il ait commencé à être terriblement lu. Nous utilisons des méthodes. qui sont implémentés à l'intérieur de la classe, ils sont donc appelés -.doingSomething (); Ce code est compréhensible, je viens de le lire de gauche à droite et je me tiens dans la tête une séquence d'événements. L'utilisation d'une fonction d'assistance rend le code lourd et moins lisible.
Eh bien, je peux implémenter une nouvelle classe et laisser les utilisateurs envelopper leur ancienne interface avec des fonctionnalités améliorées.
class CustomFuture<T> { CustomFuture(Future<T> future) : _wrapper = future; Future<T> _wrapper; Future<T> onError<E>(FutureOr<T> handleError(E error, StackTrace stack)) => _wrapper.catchError(...- ...); }
et l'appel ressemblera à ceci:
Future<String> someString = ...; CustomFuture(someString).onError((FormatException e, s) => ...).then(...);
Ça a l'air super!
Résolution d'un problème avec l'extension
Dès que nous arrêterons la programmation en pascal et reviendrons à 2019, l'implémentation de cette fonctionnalité sera réduite à cette taille:
extension CustomFuture <T> on Future<T> { Future<T> onError<E>( FutureOr<T> handleError(E error, StackTrace stack)) => this.catchError(...something clever...); }
et voici à quoi ressemblera l'appel:
Future<String> someString = ...; someString.onError((FormatException e, s) => ...).then(...);
C’est tout! La solution à ce problème n'a pris que 5 lignes de code. Toi. Vous vous demandez peut-être quel genre de magie est et comment elle fonctionne.
En fait, elle se comporte de la même manière qu'une classe wrapper, bien qu'en réalité ce ne soit qu'une fonction
statique auxiliaire. L'extension vous permet de laisser tomber l'écriture de wrapper explicite.
Ce n'est pas un wrapper
La conception de l'extension fonctionne de telle manière qu'elle ressemble à une déclaration d'une classe existante, mais agit comme s'il s'agissait d'un wrapper avec un _wrapper privé. Mais il y a un avantage par rapport à une classe wrapper, c'est d'accéder directement à la classe elle-même, plutôt que d'accéder à la classe wrapper _wrapper.
Cette fonctionnalité n'a pas été faite pour des raisons de fonctionnalités, mais comme je l'ai dit précédemment, les extensions sont en effet un moyen plus pratique d'appeler des fonctions statiques. Cela signifie qu'il n'y a pas d'objet wrapper.
Tout est statique
J'ai dit «méthodes d'extension statique» ci-dessus, et je l'ai fait pour une raison!
Dart est typé statiquement. Le compilateur connaît le type de chaque expression au moment de la compilation, donc si vous écrivez user.age (19) et age est une extension, alors le compilateur doit déterminer quel type est encapsulé dans l'objet donné afin de trouver le type de l'appel entier.
Quels problèmes peuvent survenir?
L'exemple le plus simple de problèmes d'extension est lorsque vous avez plus d'une extension dans sa portée. Fondamentalement, le gagnant est l'extension la plus proche du type d'expression réel que vous appelez le membre, avec quelques réserves.
La façon la plus simple de résoudre le problème est de connecter strictement l'extension dont vous avez besoin, ou vous pouvez utiliser l'extension explicitement:
... List list = ...; MyList(list).printlist(); SomeList(list).printlist(); ... extension MyList on List { void printlist() { print(...- ...); } } extension SomeList on List { void printlist() { print(...- ...); } }
Résumé
- Le langage Dart dispose d'un outil pratique pour étendre les fonctionnalités existantes.
- Vous pouvez étendre les méthodes, les opérateurs, les setters et les getters, mais pas les champs.
- Vous pouvez invoquer des méthodes d'extension explicitement ou - lorsqu'il n'y a pas de conflit avec un membre d'interface ou une autre extension implicitement.
- Les appels implicites fonctionnent exactement comme les appels explicites.
- Les extensions sont statiques. Tout à leur sujet est résolu sur la base de types statiques.
Si la sortie de l'extension échoue en raison d'extensions en conflit, vous pouvez effectuer l'une des opérations suivantes:
- Appliquez l'extension explicitement.
- Importez l'extension en conflit avec le préfixe, car elle n'est alors pas disponible pour les appels implicites.
- N'importez pas du tout une extension en conflit.
C’est tout! Vous pouvez utiliser l'extension à son plein potentiel.
Et bien sûr, des liens utiles:
Flutter de site WebSite Web de DartOù puis-je en savoir plus sur l'extensionChaîne télégramme où je parle de toutes les nouveautés du monde de Flutter et pas seulement