Métodos genéricos
Parte de la sección Programación Orientada a Objetos del Journey de Dart de Coddy — lección 66 de 110.
Al igual que las clases pueden ser genéricas, los métodos individuales también pueden tener sus propios parámetros de tipo. Esto es útil cuando necesitas un método flexible sin hacer que toda la clase sea genérica.
Un método genérico declara su parámetro de tipo antes del tipo de retorno:
T findFirst<T>(List<T> items) {
return items.first;
}
void main() {
var firstNumber = findFirst<int>([1, 2, 3]);
var firstWord = findFirst<String>(['hello', 'world']);
print(firstNumber); // 1
print(firstWord); // hello
}Dart a menudo puede inferir el tipo a partir de los argumentos, por lo que no siempre es necesario especificarlo explícitamente:
var result = findFirst([10, 20, 30]); // Dart infiere intLos métodos genéricos son particularmente útiles dentro de las clases cuando solo ciertas operaciones necesitan flexibilidad de tipos:
class Printer {
void printItem<T>(T item) {
print('Printing: $item');
}
List<T> duplicate<T>(T item, int count) {
return List.filled(count, item);
}
}
void main() {
var printer = Printer();
printer.printItem<String>('Hello');
printer.printItem(42); // Tipo inferido como int
var copies = printer.duplicate('Hi', 3);
print(copies); // [Hi, Hi, Hi]
}Los métodos genéricos te brindan un control detallado sobre la seguridad de tipos a nivel de método, manteniendo tus clases más simples mientras sigues beneficiándote de la comprobación de tipos en tiempo de compilación.
Desafío
FácilVamos a construir una utilidad de transformación de datos que muestre el poder de los métodos genéricos. Crearás una clase Transformer con métodos que pueden trabajar con cualquier tipo, dándote flexibilidad sin hacer que toda la clase sea genérica.
Organizarás tu código en dos archivos:
transformer.dart: Crea una claseTransformercon estos métodos genéricos:T getFirst<T>(List<T> items)- devuelve el primer elemento de una listaT getLast<T>(List<T> items)- devuelve el último elemento de una listaList<T> repeat<T>(T item, int times)- crea una lista que contiene el elemento repetido el número especificado de vecesvoid printPair<A, B>(A first, B second)- imprime dos valores en el formatoPair: [first] and [second]
main.dart: Importa tu archivo transformer y demuestra cada método genérico con diferentes tipos:- Crea una instancia de
Transformer - Usa
getFirsten[10, 20, 30]e imprime el resultado - Usa
getFirsten['apple', 'banana', 'cherry']e imprime el resultado - Usa
getLasten[1.5, 2.5, 3.5]e imprime el resultado - Usa
repeatpara crear una lista de'Hi'repetido4veces e imprime el resultado - Usa
repeatpara crear una lista de7repetido3veces e imprime el resultado - Usa
printPaircon'Name'y42 - Usa
printPaircon100ytrue
- Crea una instancia de
Observa cómo cada método declara su(s) propio(s) parámetro(s) de tipo, permitiendo que el mismo objeto Transformer trabaje con enteros, cadenas, dobles y booleanos, todo con total seguridad de tipos. El método printPair demuestra el uso de dos parámetros de tipo en un solo método.
Resultado esperado:
10
apple
3.5
[Hi, Hi, Hi, Hi]
[7, 7, 7]
Pair: Name and 42
Pair: 100 and trueHoja de referencia
Los métodos genéricos declaran parámetros de tipo antes del tipo de retorno, lo que permite que los métodos individuales sean flexibles sin que toda la clase sea genérica:
T findFirst<T>(List<T> items) {
return items.first;
}Dart puede inferir el tipo a partir de los argumentos, por lo que la especificación explícita del tipo es opcional:
var result = findFirst([10, 20, 30]); // Dart infiere intLos métodos genéricos se pueden utilizar dentro de clases no genéricas:
class Printer {
void printItem<T>(T item) {
print('Printing: $item');
}
List<T> duplicate<T>(T item, int count) {
return List.filled(count, item);
}
}Los métodos pueden declarar múltiples parámetros de tipo:
void printPair<A, B>(A first, B second) {
print('Pair: $first and $second');
}Pruébalo tú mismo
import 'transformer.dart';
void main() {
// Crea una instancia de Transformer
var transformer = Transformer();
// TODO: Usa getFirst en [10, 20, 30] e imprime el resultado
// TODO: Usa getFirst en ['apple', 'banana', 'cherry'] e imprime el resultado
// TODO: Usa getLast en [1.5, 2.5, 3.5] e imprime el resultado
// TODO: Usa repeat para crear una lista de 'Hi' repetido 4 veces e imprímela
// TODO: Usa repeat para crear una lista de 7 repetido 3 veces e imprímela
// TODO: Usa printPair con 'Name' y 42
// TODO: Usa printPair con 100 y true
}
Esta lección incluye un breve cuestionario. Empieza la lección para responderlo y registrar tu progreso.
Todas las lecciones de Programación Orientada a Objetos
1Fundamentos de POO
Archivos externosLibrerías e importacionesIntroducción a la POOClases vs. ObjetosLa palabra clave thisMétodosVariables de instanciaConceptos básicos de constructoresResumen - Calculadora sencilla4Seguridad de nulos
Introducción a la seguridad de nulosNulables vs No nulablesLos operadores ? y !Palabra clave Late y Null SafetyOperadores Null-awareNull Safety en clasesResumen - Sistema de perfil de usuario7Clases abstractas e interfaces
Clases abstractasMétodos abstractosInterfaces en DartInterfaces implícitasImplementar vs. ExtenderInterfaces múltiplesRepaso - Calculadora de figuras10Colecciones y Genéricos
Visión general de List, Set y MapColecciones con seguridad de tiposClases genéricasMétodos genéricosRestricciones genéricasIterable e IteratorResumen - Almacenamiento genérico2Constructores en Dart
Constructor por defectoConstructores nombradosListas de inicializaciónConstructores constantesConstructores de fábricaConstructores de redireccionamientoResumen - Constructor de formas5Encapsulamiento
Miembros públicos vs. privadosLa convención del prefijo _Privacidad a nivel de libreríaProfundidad en Getters y SettersOcultamiento de informaciónResumen - Registros de estudiantes8Mixins
Introducción a los MixinsCreación de MixinsUso de múltiples MixinsPalabra clave on en MixinsMixin vs HerenciaMixin vs InterfazResumen - Sistema Animal11Métodos especiales
Sobrescritura de toString()Sobrescritura de hashCode y ==Interfaz ComparableMétodo call()Sobrescritura de noSuchMethodResumen - Colección personalizada14Patrones de diseño Parte 1
Introducción a los patrones de diseñoPatrón SingletonPatrón FactoryPatrón ObserverPatrón Strategy3Propiedades de clase
Miembros de instancia vs. estáticosCampos Final y ConstVariables LateMétodos y campos estáticosGetters y SettersResumen - Gestor de cuentas bancarias6Herencia
Herencia básicaLa palabra clave superSobrescritura de métodosLa anotación @overrideLa palabra clave final en clasesConstructores y herenciaResumen - Jerarquía de empleados9Polimorfismo
Fundamentos del polimorfismoPolimorfismo mediante interfacesComprobación de tipos en tiempo de ejecuciónLos operadores is y asPalabra clave covariantResumen - Procesador de pagos12POO Asíncrona
Futures y async/awaitFundamentos de StreamsStream ControllersConstructores asíncronosAsincronía en métodos de claseRepaso - Data Fetcher15Patrones de diseño Parte 2
Patrón CommandPatrón AdapterPatrón DecoratorPatrón Template MethodPatrón StatePatrón CompositePatrón Repository