🔔 Que función recibe cada operación?
Algunhas operacións reciben un callback. Nós indicamos que facer cun elemento (ou como comparar dous) e a operación encárgase de chamar á función.
Podemos pasar unha función polo seu nome, sen (), ou escribir unha función anónima directamente nos argumentos. Non chamamos nós á función: entregámola para que a operación a use.
| Operación | Que recibe o callback? | Que debe devolver? |
|---|---|---|
map() | Un elemento | O valor transformado |
where() | Un elemento | true para conservalo ou false para descartalo |
sort() | Dous elementos | Un enteiro que indica a orde entre eles |
🔄 map(): transformar cada elemento
O método map() recibe un callback que transforma cada elemento. Por exemplo, recibe un nome e devolve ese nome en maiúsculas:
String converterMaiusculas(String nome) {
return nome.toUpperCase();
}
void main() {
final alumnos = ['Xurxo', 'Roi', 'Iria'];
// Pasamos a función: map chamaraa cos elementos da lista.
final nomes = alumnos.map(converterMaiusculas).toList();
print(nomes); // [XURXO, ROI, IRIA]
}
Tamén podemos escribir a función no propio argumento:
final alumnos = ['Xurxo', 'Roi', 'Iria'];
final nomes = alumnos
.map((String nome) => nome.toUpperCase())
.toList();
print(nomes); // O mesmo resultado que coa función con nome.
O callback (String nome) => nome.toUpperCase()
recibe cada nome e devolve ese texto en maiúsculas. Ao percorrer o resultado, por exemplo con toList(), execútase o callback para cada elemento. Tamén podemos cambiar o tipo: .map((nome) => nome.length) transforma textos en números.
map() non cambia a lista orixinal. Devolve un Iterable, unha secuencia que podemos percorrer; .toList() percorre esa secuencia e crea unha lista cos resultados. A transformación aplícase ao percorrer os elementos.
O método map() transforma datos; o tipo Map garda claves e valores. Son cousas distintas.
🧩 Un callback que captura un desconto
Os conceptos anteriores non son excluíntes. Unha mesma función pode ter as tres características:
void main() {
final prezos = [10.0, 25.0, 40.0];
double desconto = 0.20;
final prezosRebaixados = prezos
.map((double prezo) => prezo * (1 - desconto))
.toList();
print(prezosRebaixados);
// [8.0, 20.0, 32.0]
}
A función (double prezo) => prezo * (1 - desconto) é simultaneamente:
- unha función anónima, porque non ten nome;
- un callback, porque se pasa como argumento a
map(); - unha closure, porque captura a variable exterior
desconto.
🔍 where(): conservar os elementos que cumpren unha condición
O método where() emprega un callback que debe devolver true ou false. Non transforma o elemento: decide se se conserva.
bool estaAprobada(int nota) {
return nota >= 5; // true: conservar; false: descartar.
}
void main() {
final notas = [4, 7, 9];
final aprobadas = notas.where(estaAprobada).toList();
print(aprobadas); // [7, 9]
}
A mesma operación cunha función anónima:
void main() {
final notas = [3, 7, 5, 9, 4];
final aprobadas = notas
.where((int nota) => nota >= 5)
.toList();
print(aprobadas); // [7, 5, 9]
}
O callback execútase para cada nota:
- se devolve
true, a nota inclúese no resultado; - se devolve
false, descártase.
Como map(), where() devolve un Iterable e non modifica a lista orixinal. Usamos toList() para obter a nova lista.
🔡 sort(): ordenar a propia lista
sort() cambia a orde dos elementos da lista existente. Non devolve unha lista nova: chamámolo e despois usamos a mesma lista.
Con números ou textos podemos usar sort() sen argumentos para a orde predeterminada. Por exemplo, [4, 9, 7] pasa a [4, 7, 9].
Para escoller a orde, pasamos un comparador. Recibe dous elementos, a e b, e debe devolver:
| Resultado | Significado |
|---|---|
| Un número negativo | a debe ir antes ca b. |
| Cero | Son equivalentes para esta ordenación. |
| Un número positivo | a debe ir despois de b. |
compareTo() xa devolve un enteiro con ese significado:
int compararNotas(int a, int b) {
return a.compareTo(b); // Orde de menor a maior.
}
void main() {
final notas = [4, 9, 7];
notas.sort(compararNotas); // Pasamos o comparador polo nome.
print(notas); // [4, 7, 9]
notas.sort((a, b) => b.compareTo(a)); // Invertemos a comparación.
print(notas); // [9, 7, 4]
}
Por exemplo, 4.compareTo(9) é negativo: o 4 vai antes do 9. O comparador pode chamarse varias veces coas parellas que necesite a ordenación. Non debe devolver true ou false, senón un int.
Se queremos ordenar sen modificar a lista orixinal, primeiro facemos unha copia:
final notas = [4, 9, 7];
final ordenadas = List<int>.of(notas); // Creamos outra lista.
ordenadas.sort();
print(notas); // [4, 9, 7]
print(ordenadas); // [4, 7, 9]
Tamén podemos ordenar rexistros polo campo que nos interese:
final alumnos = [(nome: 'Roi', nota: 6), (nome: 'Iria', nota: 9)];
alumnos.sort((a, b) => b.nota.compareTo(a.nota)); // Maior nota primeiro.
print(alumnos);
🔔 forEach(): facer unha acción por elemento
Recibe un callback e execútao unha vez por elemento. A acción non ten que devolver un resultado: forEach() non crea unha colección cos valores devoltos.
void saudarAlumno(String nome) {
print('Ola, $nome'); // Acción que facemos con cada alumno.
}
void main() {
final alumnos = ['Xurxo', 'Roi', 'Iria'];
alumnos.forEach(saudarAlumno); // Pasamos a función polo nome.
}
A mesma operación cunha función anónima:
void main() {
final alumnos = ['Xurxo', 'Roi', 'Iria'];
alumnos.forEach((String nome) {
print('Ola, $nome'); // Unha chamada por alumno.
});
}
Para percorrer unha colección e executar instrucións tamén podemos usar for-in, que adoita resultar claro. Escolle map() se queres transformar datos e obter os resultados, e forEach() se só queres facer unha acción por elemento.
🏗️ Construtores de listas
Ademais de escribir [...], podemos crear listas con estas formas, chamadas construtores.
🔁 List.filled(): repetir un valor
final numeros = List<int>.filled(5, 4); // Cinco elementos co valor 4.
print(numeros); // [4, 4, 4, 4, 4]
numeros[0] = 8; // Podemos cambiar un elemento.
// numeros.add(4); // Fallaría: por defecto, o tamaño é fixo.
print(numeros); // [8, 4, 4, 4, 4]
O primeiro argumento indica a cantidade de elementos e o segundo, o valor inicial. Para gardar o texto '4', usariamos List<String>.filled(5, '4').
Se queremos poder engadir ou eliminar elementos, indicamos growable: true:
final numeros = List<int>.filled(5, 4, growable: true);
numeros.add(9); // Agora a lista pode aumentar de tamaño.
print(numeros); // [4, 4, 4, 4, 4, 9]
final impide asignar outra lista á variable; growable indica se podemos cambiar o tamaño da lista. Son cousas distintas.
🔢 List.generate(): calcular cada elemento
Recibe a cantidade e unha función que recibe o índice, empezando en cero, e devolve o valor desa posición:
final numeros = List<int>.generate(5, (indice) => indice + 1);
print(numeros); // [1, 2, 3, 4, 5]
A función recibe 0, 1, 2, 3 e 4; ao sumar un, xera os valores do 1 ao 5. Tamén se pode pasar unha función definida fóra, polo nome, como en map(). Por defecto esta lista pode cambiar de tamaño; podemos indicar growable: false.
Coidado ao repetir listas: List.filled() repite o mesmo valor. Se ese valor é unha lista modificable, todas as posicións comparten esa lista. Para crear unha lista independente en cada posición, usa List.generate():
final grupos = List<List<String>>.generate(2, (_) => <String>[]);
// Ignoramos o índice con _: só queremos unha lista nova cada vez.
grupos[0].add('Xurxo');
print(grupos); // [[Xurxo], []]
📋 List.of(): facer unha copia
List<int>.of(notas) crea outra lista cos elementos de notas, como vimos en sort(). Copia a lista, pero non crea copias independentes dos obxectos que contén.
🧱 Construír listas con ..., if e for
Estas formas serán útiles para crear listas de widgets en Flutter:
...listaengade os seus elementos, non a lista como un único elemento....?listafai o mesmo, pero non engade nada se a lista énull.ifinclúe un elemento segundo unha condición.forxera elementos percorrendo outra colección.
🧪 Exemplo completo
🔗 Ver o código en DartPad — https://dartpad.dev/?id=fb37221c89b484634cf0b2b2b46ff2e2
📚 Consulta: map — https://api.dart.dev/dart-core/Iterable/map.html, where — https://api.dart.dev/dart-core/Iterable/where.html e sort — https://api.dart.dev/dart-core/List/sort.html.
📚 Construtores: List.filled — https://api.dart.dev/dart-core/List/List.filled.html, List.generate — https://api.dart.dev/dart-core/List/List.generate.html e List.of — https://api.dart.dev/dart-core/List/List.of.html.