Erweiterung in Dart (Flutter)

In einer kürzlich erschienenen Version von Dart 2.6 hat die Sprache eine neue Funktion, statische Erweiterung oder statische Erweiterungsmethoden eingeführt, mit deren Hilfe Sie vorhandenen Typen neue Methoden hinzufügen können. Warum brauchen wir eine Verlängerung? Wie benutzt man sie und wofür sind sie gut?



Einleitung


Was ist Erweiterung im Allgemeinen? Extension ist syntaktischer Zucker, der eine vorhandene Klasse an einer anderen Stelle als das Klassendeklarationsmodul erweitert.

In der Programmierung gibt es Erweiterungsmethoden schon seit langer Zeit, so dass sie sich dem Dart widmen mussten. Die Erweiterung wird aktiv in Sprachen wie C #, Java über Manifold, Swift, Kotlin und vielen anderen verwendet.

Das problem


Nehmen wir an, wir haben eine catchError-Methode, die einfach schrecklich ist und in eine neue coole Funktion umgeschrieben werden muss. Angenommen, er verwendet eine Funktion eines beliebigen Typs als Argument für eine Stelle einer streng typisierten Funktion oder um den Typ einer Funktion zu überprüfen, und dies geschieht, weil dies vor 8 Monaten bei der Entwicklung dieser Funktionalität logisch war.

Das erste, was mir in den Sinn kommt, ist, diese Funktion neu zu schreiben. Hier stehen wir jedoch vor dem Problem, dass sie im Projekt zu häufig auftritt und eine Änderung der Funktion zur Inoperabilität des gesamten Projekts führt.

Nun, wenn die erste Option nicht für uns ist. Aus logischen Gründen kann ich dann eine neue Future-Funktion implementieren, die alle meine Anforderungen erfüllt.

abstract class Future<T> { ... /// Catches any [error] of type [E]. Future<T> onError<E>(FutureOr<T> handleError(E error, StackTrace stack)) => this.catchError(...   -  ...); } ... } 

und ich werde sie so nennen:

 Future<String> someString = ...; someString.onError((FormatException e, s) => ...).then(...); 

Leider kann ich diese Funktion nicht zur Future-Klasse hinzufügen. Wenn ich das tue, füge ich es auch der Future-Schnittstelle hinzu, und jede andere Klasse, die diese Schnittstelle implementiert, ist unvollständig und wird nicht mehr kompiliert.

Nun, eine andere Möglichkeit besteht darin, eine Drittanbieterfunktion zu implementieren, die so aussieht:

 Future<T> onFutureError<T, E>(Future<T> source, FutureOr<T> handleError(E error, StackTrace stack)) => source.catchError(... - ...); 

Und ihr Anruf würde so aussehen:

 Future<String> someString = ...; onFutureError(someString, (FormatException e, s) => ...).then(...); 

Super, alles funktioniert! Aber es ist traurig, dass es anfing, schrecklich gelesen zu werden. Wir wenden Methoden an. die in der Klasse implementiert sind, heißen also -.doingSomething (); Dieser Code ist verständlich, ich lese ihn einfach von links nach rechts und stelle mir eine Abfolge von Ereignissen vor. Die Verwendung einer Hilfsfunktion macht den Code umständlich und weniger lesbar.

Nun, dann kann ich eine neue Klasse implementieren und Benutzern erlauben, ihre alte Schnittstelle mit verbesserter Funktionalität zu verpacken.

 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(...-     ...); } 

und der Aufruf wird so aussehen:

 Future<String> someString = ...; CustomFuture(someString).onError((FormatException e, s) => ...).then(...); 

Sieht gut aus!

Ein Problem mit der Erweiterung lösen


Sobald wir die Programmierung in Pascal beenden und zu 2019 zurückkehren, wird die Implementierung dieser Funktionalität auf diese Größe reduziert:

 extension CustomFuture <T> on Future<T> { Future<T> onError<E>( FutureOr<T> handleError(E error, StackTrace stack)) => this.catchError(...something clever...); } 

und so sieht der anruf aus:

 Future<String> someString = ...; someString.onError((FormatException e, s) => ...).then(...); 

Das ist alles! Die Lösung für dieses Problem benötigte nur 5 Codezeilen. Sie Sie mögen sich fragen, was für eine Art von Magie ist und wie sie funktioniert.

Tatsächlich verhält es sich wie eine Wrapper-Klasse, obwohl es sich in Wirklichkeit nur um eine statische Hilfsfunktion handelt. Mit Extension können Sie explizites Wrapper-Schreiben loslassen.

Dies ist kein Wrapper


Das Erweiterungsdesign funktioniert so, dass es wie eine Deklaration einer vorhandenen Klasse aussieht, sich jedoch so verhält, als wäre es ein Wrapper mit einem privaten _wrapper. Gegenüber einer Wrapper-Klasse gibt es jedoch einen Vorteil: Es wird direkt auf die Klasse zugegriffen, anstatt auf die Wrapper-Klasse _wrapper.

Diese Funktion wurde nicht aus Gründen der Funktionen erstellt, aber wie ich bereits sagte, sind Erweiterungen in der Tat eine bequemere Möglichkeit, statische Funktionen aufzurufen. Dies bedeutet, dass kein Wrapper-Objekt vorhanden ist.

Es ist alles statisch


Ich habe oben "statische Erweiterungsmethoden" gesagt und das aus einem bestimmten Grund!

Dart ist statisch geschrieben. Der Compiler kennt den Typ jedes Ausdrucks zur Kompilierungszeit. Wenn Sie also user.age (19) schreiben und age eine Erweiterung ist, muss der Compiler herausfinden, welcher Typ in das angegebene Objekt eingeschlossen ist, um den Typ des gesamten Aufrufs zu ermitteln.

Welche Probleme können auftreten?


Das einfachste Beispiel für Probleme mit der Erweiterung ist, wenn Sie mehr als eine Erweiterung im Geltungsbereich haben. Grundsätzlich ist der Gewinner die Erweiterung, die dem tatsächlichen Ausdruckstyp am nächsten kommt, den Sie mit einigen Vorbehalten als Mitglied anrufen.

Der einfachste Weg, das Problem zu lösen, besteht darin, die von Ihnen benötigte Erweiterung zu verbinden, oder Sie können die Erweiterung explizit verwenden:

 ... List list = ...; MyList(list).printlist(); SomeList(list).printlist(); ... extension MyList on List { void printlist() { print(...- ...); } } extension SomeList on List { void printlist() { print(...-  ...); } } 

Zusammenfassung


  • Die Dart-Sprache verfügt über ein praktisches Tool zur Erweiterung bestehender Funktionen.
  • Sie können Methoden, Operatoren, Setter und Getter erweitern, jedoch keine Felder.
  • Sie können Erweiterungsmethoden explizit aufrufen oder - wenn kein Konflikt mit einem Schnittstellenmitglied oder einer anderen Erweiterung vorliegt - implizit.
  • Implizite Aufrufe funktionieren genauso wie explizite Aufrufe.
  • Erweiterungen sind statisch. Alles an ihnen wird auf der Basis statischer Typen gelöst.

Wenn die Ausgabe der Erweiterung aufgrund von Konflikten mit Erweiterungen fehlschlägt, haben Sie folgende Möglichkeiten:

  1. Wenden Sie die Erweiterung explizit an.
  2. Importieren Sie die in Konflikt stehende Erweiterung mit dem Präfix, da sie dann nicht für implizite Aufrufe verfügbar ist.
  3. Importieren Sie überhaupt keine widersprüchlichen Erweiterungen.

Das ist alles! Sie können die Erweiterung optimal nutzen.

Und natürlich nützliche Links:

Website flattern
Dart Webseite
Wo kann ich mehr über die Erweiterung lesen?
Telegrammkanal, in dem ich über die neuesten Entwicklungen in der Welt von Flutter spreche und nicht nur

Source: https://habr.com/ru/post/de476930/


All Articles