Extensi贸n en Dart (Flutter)

En una versi贸n reciente de Dart 2.6, el lenguaje introdujo una nueva funci贸n, extensi贸n est谩tica o m茅todos de extensi贸n est谩tica, que le permite agregar nuevos m茅todos a los tipos existentes. 驴Por qu茅 necesitamos extensi贸n? 驴C贸mo usarlos y para qu茅 sirven?



Introduccion


Para empezar, 驴qu茅 es la extensi贸n en general? La extensi贸n es az煤car sint谩ctica que extiende una clase existente en un lugar diferente del m贸dulo de declaraci贸n de clase.

En programaci贸n, los m茅todos de extensi贸n han existido durante mucho tiempo, por lo que tuvieron que lanzarse. La extensi贸n se usa activamente en lenguajes como C #, Java a trav茅s de Manifold, Swift, Kotlin y muchos otros.

El problema


Digamos que tenemos un m茅todo catchError, que es simplemente horrible y necesita reescribirse para una nueva funci贸n genial. Suponga que usa una funci贸n de cualquier tipo como argumento para un lugar de una funci贸n estrictamente tipada o para verificar el tipo de una funci贸n, y esto sucede porque hace 8 meses cuando desarrollaba esta funcionalidad era l贸gico en ese momento.

Lo primero que viene a la mente es reescribir esta funci贸n, pero aqu铆 nos enfrentamos con el problema de que ocurre con demasiada frecuencia en el proyecto, y cambiar la funci贸n conducir谩 a la inoperancia de todo el proyecto.

Bueno, si la primera opci贸n no es para nosotros. adecuado, por razones l贸gicas, entonces puedo implementar una nueva funci贸n Futuro que cumpla con todos mis requisitos.

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

y la llamar茅 as铆:

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

Desafortunadamente, no puedo agregar esta funci贸n a la clase Future. Si hago esto, tambi茅n lo agregar茅 a la interfaz Future, y cualquier otra clase que implemente esta interfaz estar谩 incompleta y ya no se compilar谩.

Bueno, otra opci贸n es implementar una funci贸n de terceros que se ver谩 as铆:

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

Y su llamada se ver铆a as铆:

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

隆Genial, todo funciona! Pero es triste que haya comenzado a leerse terriblemente. Usamos m茅todos que se implementan dentro de la clase, por lo que se llaman -.doingSomething (); Este c贸digo es comprensible, lo acabo de leer de izquierda a derecha y tengo en mi cabeza una secuencia de eventos. El uso de una funci贸n auxiliar hace que el c贸digo sea engorroso y menos legible.

Bueno, entonces puedo implementar una nueva clase y dejar que los usuarios envuelvan su interfaz anterior con una funcionalidad mejorada.

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

y la llamada se ver谩 as铆:

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

Se ve genial!

Resolviendo un problema con la extensi贸n


Tan pronto como detengamos la programaci贸n en pascal y regresemos a 2019, la implementaci贸n de esta funcionalidad se reducir谩 a este tama帽o:

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

y as铆 es como se ver谩 la llamada:

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

Eso es todo! La soluci贸n a este problema tom贸 solo 5 l铆neas de c贸digo. Usted Te preguntar谩s qu茅 tipo de magia es y c贸mo funciona.

De hecho, se comporta de la misma manera que una clase contenedora, aunque en realidad es solo una funci贸n est谩tica auxiliar. La extensi贸n le permite dejar de lado la escritura expl铆cita de envoltorios.

Esto no es un envoltorio


El dise帽o de la extensi贸n funciona de tal manera que parece una declaraci贸n de una clase existente, pero act煤a como si fuera un contenedor con un _wrapper privado. Pero hay una ventaja en comparaci贸n con una clase de contenedor: esto es acceder a la clase directamente, en lugar de acceder a la clase de contenedor _wrapper.

Esta caracter铆stica no se hizo por el bien de las caracter铆sticas, pero como dije antes, las extensiones son de hecho una forma m谩s conveniente de llamar a funciones est谩ticas. Esto significa que no hay ning煤n objeto contenedor.

Todo es est谩tico


Dije "m茅todos de extensi贸n est谩tica" arriba, 隆y lo hice por una raz贸n!

Dart est谩 est谩ticamente escrito. El compilador conoce el tipo de cada expresi贸n en el momento de la compilaci贸n, por lo que si escribe user.age (19) y age es una extensi贸n, entonces el compilador debe averiguar qu茅 tipo est谩 envuelto en el objeto dado para encontrar el tipo de la llamada completa.

驴Qu茅 problemas pueden surgir?


El ejemplo m谩s simple de problemas con la extensi贸n es cuando tiene m谩s de una extensi贸n en su alcance. B谩sicamente, el ganador es la extensi贸n m谩s cercana al tipo real de expresi贸n que est谩 llamando al miembro, con algunas reservas.

La forma m谩s f谩cil de resolver el problema es conectar estrictamente la extensi贸n que necesita, o puede usar la extensi贸n expl铆citamente:

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

Resumen


  • El lenguaje dardo tiene una herramienta conveniente para expandir la funcionalidad existente.
  • Puede ampliar m茅todos, operadores, establecedores y captadores, pero no campos.
  • Puede invocar m茅todos de extensi贸n expl铆citamente o, cuando no haya conflicto con un miembro de la interfaz u otra extensi贸n, impl铆citamente.
  • Las llamadas impl铆citas funcionan igual que las llamadas expl铆citas.
  • Las extensiones son est谩ticas. Todo sobre ellos se resuelve sobre la base de tipos est谩ticos.

Si la salida de la extensi贸n falla debido a extensiones en conflicto, puede hacer lo siguiente:

  1. Aplica la extensi贸n expl铆citamente.
  2. Importe la extensi贸n conflictiva con el prefijo, porque no est谩 disponible para llamadas impl铆citas.
  3. No importe una extensi贸n conflictiva en absoluto.

Eso es todo! Puede usar la extensi贸n en todo su potencial.

Y, por supuesto, enlaces 煤tiles:

Aleteo del sitio web
Sitio web de Dart
驴D贸nde puedo leer m谩s sobre la extensi贸n?
Canal de Telegram donde hablo de todo lo m谩s nuevo en el mundo de Flutter y no solo

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


All Articles