Diferencia entre revisiones de «Flutter DART Funciones»

De MediaWiki
Ir a la navegación Ir a la búsqueda
 
(No se muestran 6 ediciones intermedias del mismo usuario)
Línea 1: Línea 1:
−
==Introducción==
 
−
 
−
* Las funciones en DART funcionan igual que en cualquier lenguaje de programación orientado a objetos, por lo que no voy a explicar nada del mismo.
 
−
: Como comenté, este curso está orientada a alumnos que ya saben programar en algún lenguaje..
 
−
 
−
* Veamos un ejemplo de función con parámetros:
 
−
:<syntaxhighlight lang="java" enclose="div" highlight="1-3" >
 
−
double sumarValores(double val1, double val2){
 
−
  return val1+val2;
 
−
}
 
−
 
−
void main() {
 
−
 
−
  final num1 = 10.32;
 
−
  final num2 = 1.35;
 
−
 
 
−
  print(sumarValores(num1,num2));
 
−
}
 
−
</syntaxhighlight>
 
−
 
−
 
−
<br />
 
−
==Paso de parámetros==
 
−
 
−
* Al igual que otros lenguajes podemos pasar datos a las funciones empleando los parámetros.
 
−
: Como ya vimos, [https://wiki.cifprodolfoucha.es/index.php?title=Flutter_DART_variables_-_tipos_de_datos#Valores_nulos podemos definir los parámetros para que acepten valores nulos].
 
−
 
−
<br />
 
−
 
−
===Por valor/referencia===
 
−
 
−
* Al igual que en Java, el paso va a ser por valor en los tipos de datos 'simples' como: int, double, bool y String (también String :) )
 
−
: Los valores que sean objetos de una clase serán pasados por referencia.
 
−
 
−
:<syntaxhighlight lang="java" enclose="div" highlight="" >
 
−
class Pelota {
 
−
  double? peso;
 
−
  String? id;
 
−
}
 
−
 
−
 
−
void modificarValores(Pelota pelota, int valor,String cadena){
 
−
 
 
−
  valor = 10;
 
−
  pelota.peso = 100.2;
 
−
  pelota.id = 'P2';
 
−
  cadena = 'NUEVA CADENA';
 
−
 
 
−
}
 
−
void main() {
 
−
 
 
−
  var valorPrueba = 5;
 
−
  var cadena = 'VIEJA CADENA';
 
−
  Pelota pel = new Pelota();
 
−
  pel.id='P1';
 
−
  pel.peso = 50.34;
 
−
 
 
−
  modificarValores(pel, valorPrueba,cadena);
 
−
 
 
−
  print('El valor numérico no es modificado ya que lo pasa por valor: $valorPrueba');
 
−
  print('El valor cadena no es modificado ya que lo pasa por valor: $cadena');
 
−
  print('El objeto es modificado ya que lo pasa por referencia: ${pel.id} -- ${pel.peso}');
 
−
 
−
}
 
−
</syntaxhighlight>
 
−
 
−
 
−
 
−
<br />
 
−
 
−
===Parámetros optativos===
 
−
 
−
* Podemos definir un parámetro como optativo mediante el empleo de '''[  ]''' de la forma siguiente:
 
−
:<syntaxhighlight lang="java" enclose="div" highlight="1" >
 
−
void imprimirMensaje([String mensaje='Nada enviado']){
 
−
 
 
−
  print(mensaje);
 
−
}
 
−
 
−
void main() {
 
−
 
 
−
  imprimirMensaje();  // No enviamos el dato, imprime el valor por defecto
 
−
 
 
−
  imprimirMensaje('Nuevo Mensaje'); 
 
−
}
 
−
</syntaxhighlight>
 
−
 
−
* Fijarse que tenemos que establecer un valor por defecto, a no ser que permitamos que el parámetro pueda tener valor nulo, que será el valor que tenga cuando no se envíe dato a la función:
 
−
:<syntaxhighlight lang="java" enclose="div" highlight="1" >
 
−
void imprimirMensaje([String? mensaje]){
 
−
 
−
}
 
−
</syntaxhighlight>
 
−
 
−
 
−
* En caso de que la función lleve parámetros obligatorios y optativos, deben de <u>definirse primero los obligatorios</u>:
 
−
:<syntaxhighlight lang="java" enclose="div" highlight="1" >
 
−
void imprimirMensaje(int param1, [String? mensaje]){
 
−
 
−
}
 
−
</syntaxhighlight>
 
−
 
−
 
−
 
−
<br />
 
−
 
 
==Introducción==
 
==Introducción==
  
Línea 152: Línea 46:
 
:<syntaxhighlight lang="dart" enclose="div">
 
:<syntaxhighlight lang="dart" enclose="div">
 
class Pelota {
 
class Pelota {
−
double? peso;
+
  double? peso;
−
String? id;
+
  String? id;
 
}
 
}
  
 
void modificarValores(
 
void modificarValores(
−
Pelota pelota,
+
  Pelota pelota,
−
int valor,
+
  int valor,
−
String cadena,
+
  String cadena,
 
) {
 
) {
−
valor = 10;
+
  valor = 10;
−
cadena = 'NUEVA CADENA';
+
  cadena = 'NUEVA CADENA';
  
−
pelota.peso = 100.2;
+
  pelota.peso = 100.2;
−
pelota.id = 'P2';
+
  pelota.id = 'P2';
 
}
 
}
  
 
void main() {
 
void main() {
−
var valorPrueba = 5;
+
  var valorPrueba = 5;
−
var cadena = 'VIEJA CADENA';
+
  var cadena = 'VIEJA CADENA';
  
−
final pelota = Pelota();
+
  final pelota = Pelota();
−
pelota.id = 'P1';
 
−
pelota.peso = 50.34;
 
  
−
modificarValores(
+
  pelota.id = 'P1';
−
pelota,
+
  pelota.peso = 50.34;
−
valorPrueba,
+
 
−
cadena,
+
  modificarValores(
−
);
+
    pelota,
 +
    valorPrueba,
 +
    cadena,
 +
  );
 +
 
 +
  print('Valor numérico: $valorPrueba');
 +
  print('Cadena: $cadena');
 +
  print('Objeto: ${pelota.id} -- ${pelota.peso}');
 +
}
 +
</syntaxhighlight>
  
−
print('Valor numérico: $valorPrueba');
 
−
print('Cadena: $cadena');
 
−
print('Objeto: ${pelota.id} -- ${pelota.peso}');
 
−
} </syntaxhighlight>
 
  
 
: Después de ejecutar la función:
 
: Después de ejecutar la función:
Línea 202: Línea 99:
 
{{#ev:youtube|9a2ANaIjOa0}}
 
{{#ev:youtube|9a2ANaIjOa0}}
 
</center>
 
</center>
 +
 +
  
 
* Podemos definir parámetros posicionales opcionales escribiéndolos entre corchetes <code>[ ]</code>.
 
* Podemos definir parámetros posicionales opcionales escribiéndolos entre corchetes <code>[ ]</code>.
Línea 333: Línea 232:
  
 
: Los parámetros posicionales se escriben antes que los parámetros con nombre:
 
: Los parámetros posicionales se escriben antes que los parámetros con nombre:
−
 
+
:<syntaxhighlight lang="dart" enclose="div" highlight="2,3">
−
:<syntaxhighlight lang="dart" enclose="div" highlight="1">
 
 
void imprimirMensaje(
 
void imprimirMensaje(
−
int numero, {
+
  int numero, {
−
String? mensaje,
+
    String? mensaje,
−
}) {
+
  }
−
print(
+
) {
−
'El número es $numero y el mensaje es $mensaje',
+
  print(
−
);
+
    'El número es $numero y el mensaje es $mensaje',
 +
  );
 
}
 
}
  
 
void main() {
 
void main() {
−
imprimirMensaje(
+
  imprimirMensaje(
−
10,
+
    10,
−
mensaje: 'Mensaje',
+
    mensaje: 'Mensaje',
−
);
+
  );
−
} </syntaxhighlight>
+
}
 +
</syntaxhighlight>
  
 
<br />
 
<br />
Línea 991: Línea 891:
 
Emplea <code>List.generate</code> para realizar los siguientes ejercicios:
 
Emplea <code>List.generate</code> para realizar los siguientes ejercicios:
  
−
:* Genera una lista de 100 números enteros aleatorios comprendidos entre 1 y 100.
+
:* Genera una lista de 100 números enteros aleatorios comprendidos entre 1 y 100. Emplea la clase Random.
 
:* Genera una lista con los números comprendidos entre 1 y 100 y haz que tenga longitud fija, de forma que no puedan añadirse ni eliminarse elementos.
 
:* Genera una lista con los números comprendidos entre 1 y 100 y haz que tenga longitud fija, de forma que no puedan añadirse ni eliminarse elementos.
 
:* Dado un número, genera una lista con los cuadrados de todos los números comprendidos entre 1 y dicho número. En este caso, la lista debe permitir añadir nuevos elementos.
 
:* Dado un número, genera una lista con los cuadrados de todos los números comprendidos entre 1 y dicho número. En este caso, la lista debe permitir añadir nuevos elementos.
Línea 1007: Línea 907:
  
 
<br />
 
<br />
 +
  
 
===Soluciones de los ejercicios propuestos===
 
===Soluciones de los ejercicios propuestos===
Línea 1014: Línea 915:
 
:<syntaxhighlight lang="dart" enclose="div">
 
:<syntaxhighlight lang="dart" enclose="div">
 
String devolverElementoLista({
 
String devolverElementoLista({
−
int posicion = 0,
+
int posicion = 0,
−
required List<String> lista,
+
required List<String> lista,
 
}) {
 
}) {
−
if (lista.isEmpty) {
+
if (lista.isEmpty) {
−
return 'Sin datos';
+
return 'Sin datos';
−
}
+
}
  
−
if (
+
if (
−
posicion < 0 ||
+
posicion < 0 ||
−
posicion >= lista.length
+
posicion >= lista.length
−
) {
+
) {
−
return 'Índice fuera de rango';
+
return 'Índice fuera de rango';
−
}
+
}
  
−
return lista[posicion];
+
return lista[posicion];
 
}
 
}
  
 
void main() {
 
void main() {
−
final lista = <String>[
+
final lista = <String>[
−
'Uno',
+
'Uno',
−
'Dos',
+
'Dos',
−
'Tres',
+
'Tres',
−
'Cuatro',
+
'Cuatro',
−
];
+
];
  
−
print(
+
print(
−
devolverElementoLista(
+
devolverElementoLista(
−
lista: lista,
+
lista: lista,
−
),
+
),
−
);
+
);
  
−
print(
+
print(
−
devolverElementoLista(
+
devolverElementoLista(
−
posicion: 2,
+
posicion: 2,
−
lista: lista,
+
lista: lista,
−
),
+
),
−
);
+
);
  
−
print(
+
print(
−
devolverElementoLista(
+
devolverElementoLista(
−
lista: lista,
+
lista: lista,
−
posicion: 4,
+
posicion: 4,
−
),
+
),
−
);
+
);
  
−
print(
+
print(
−
devolverElementoLista(
+
devolverElementoLista(
−
posicion: -1,
+
posicion: -1,
−
lista: lista,
+
lista: lista,
−
),
+
),
−
);
+
);
−
} </syntaxhighlight>
+
}
 +
</syntaxhighlight>
  
 
<br />
 
<br />
Línea 1073: Línea 975:
 
:<syntaxhighlight lang="dart" enclose="div">
 
:<syntaxhighlight lang="dart" enclose="div">
 
int getNumPlatosMasCaros({
 
int getNumPlatosMasCaros({
−
required Map<int, double> mapa,
+
required Map<int, double> mapa,
−
required double precio,
+
required double precio,
 
}) {
 
}) {
−
return mapa.values
+
return mapa.values
−
.where(
+
.where(
−
(precioMapa) => precioMapa > precio,
+
(precioMapa) => precioMapa > precio,
−
)
+
)
−
.length;
+
.length;
 
}
 
}
  
 
void main() {
 
void main() {
−
final precios = <int, double>{
+
final precios = <int, double>{
−
1: 10.34,
+
1: 10.34,
−
2: 3.24,
+
2: 3.24,
−
3: 24.99,
+
3: 24.99,
−
4: 17.35,
+
4: 17.35,
−
};
+
};
  
−
precios.addAll({
+
precios.addAll({
−
5: 9.23,
+
5: 9.23,
−
6: 2.22,
+
6: 2.22,
−
});
+
});
  
−
print(precios);
+
print(precios);
  
−
final ultimaClave = precios.keys.last;
+
final ultimaClave = precios.keys.last;
−
precios.remove(ultimaClave);
+
precios.remove(ultimaClave);
  
−
precios.forEach((clave, valor) {
+
precios.forEach((clave, valor) {
−
if (valor < 5) {
+
if (valor < 5) {
−
print(
+
print(
−
'La clave $clave tiene un precio de $valor',
+
'La clave $clave tiene un precio de $valor',
−
);
+
);
−
}
+
}
−
});
+
});
  
−
const precioReferencia = 10.0;
+
const precioReferencia = 10.0;
  
−
final numPlatos = getNumPlatosMasCaros(
+
final numPlatos = getNumPlatosMasCaros(
−
mapa: precios,
+
mapa: precios,
−
precio: precioReferencia,
+
precio: precioReferencia,
−
);
+
);
  
−
print(
+
print(
−
'Número de platos con un precio superior '
+
'Número de platos con un precio superior '
−
'a $precioReferencia euros: $numPlatos',
+
'a $precioReferencia euros: $numPlatos',
−
);
+
);
−
} </syntaxhighlight>
+
}
 +
</syntaxhighlight>
  
 
<br />
 
<br />
Línea 1128: Línea 1031:
 
:<syntaxhighlight lang="dart" enclose="div">
 
:<syntaxhighlight lang="dart" enclose="div">
 
void buscarCadena(
 
void buscarCadena(
−
Set<String> conjunto,
+
Set<String> conjunto,
−
String cadena,
+
String cadena,
 
) {
 
) {
−
final encontrados = conjunto.where(
+
final encontrados = conjunto.where(
−
(elemento) => elemento.contains(cadena),
+
(elemento) => elemento.contains(cadena),
−
);
+
);
  
−
for (final elemento in encontrados) {
+
for (final elemento in encontrados) {
−
print('Encontrado: $elemento');
+
print('Encontrado: $elemento');
−
}
+
}
 
}
 
}
  
 
void main() {
 
void main() {
−
final equipo = <String>{
+
final equipo = <String>{
−
'Base',
+
'Base',
−
'Alero',
+
'Alero',
−
'Pivot',
+
'Pivot',
−
'Escolta',
+
'Escolta',
−
};
+
};
  
−
var cadenaBusqueda = 'as';
+
var cadenaBusqueda = 'as';
  
−
print(
+
print(
−
'Cadena de búsqueda: $cadenaBusqueda',
+
'Cadena de búsqueda: $cadenaBusqueda',
−
);
+
);
  
−
buscarCadena(
+
buscarCadena(
−
equipo,
+
equipo,
−
cadenaBusqueda,
+
cadenaBusqueda,
−
);
+
);
  
−
cadenaBusqueda = 's';
+
cadenaBusqueda = 's';
  
−
print(
+
print(
−
'Cadena de búsqueda: $cadenaBusqueda',
+
'Cadena de búsqueda: $cadenaBusqueda',
−
);
+
);
  
−
buscarCadena(
+
buscarCadena(
−
equipo,
+
equipo,
−
cadenaBusqueda,
+
cadenaBusqueda,
−
);
+
);
−
} </syntaxhighlight>
+
}
 +
</syntaxhighlight>
  
 
<br />
 
<br />
Línea 1177: Línea 1081:
 
:<syntaxhighlight lang="dart" enclose="div">
 
:<syntaxhighlight lang="dart" enclose="div">
 
String sonMayores({
 
String sonMayores({
−
double numero = 0,
+
double numero = 0,
−
required List<double> lista,
+
required List<double> lista,
 
}) =>
 
}) =>
−
lista.every(
+
lista.every(
−
(elemento) => elemento > numero,
+
(elemento) => elemento > numero,
−
)
+
)
−
? 'SI'
+
? 'SI'
−
: 'NO';
+
: 'NO';
  
 
void main() {
 
void main() {
−
final listaNumeros = <double>[
+
final listaNumeros = <double>[
−
10.0,
+
10.0,
−
11.22,
+
11.22,
−
15.0,
+
15.0,
−
7.0,
+
7.0,
−
3.44,
+
3.44,
−
];
+
];
  
−
var numeroReferencia = 2.0;
+
var numeroReferencia = 2.0;
  
−
print(
+
print(
−
'Todos los números de la lista son mayores '
+
'Todos los números de la lista son mayores '
−
'a $numeroReferencia: '
+
'a $numeroReferencia: '
−
'${sonMayores(
+
'${sonMayores(
−
numero: numeroReferencia,
+
numero: numeroReferencia,
−
lista: listaNumeros,
+
lista: listaNumeros,
−
)}',
+
)}',
−
);
+
);
  
−
numeroReferencia = 12.0;
+
numeroReferencia = 12.0;
  
−
print(
+
print(
−
'Todos los números de la lista son mayores '
+
'Todos los números de la lista son mayores '
−
'a $numeroReferencia: '
+
'a $numeroReferencia: '
−
'${sonMayores(
+
'${sonMayores(
−
lista: listaNumeros,
+
lista: listaNumeros,
−
numero: numeroReferencia,
+
numero: numeroReferencia,
−
)}',
+
)}',
−
);
+
);
−
} </syntaxhighlight>
+
}
 +
</syntaxhighlight>
  
 
<br />
 
<br />
Línea 1226: Línea 1131:
  
 
void main() {
 
void main() {
−
final random = Random();
+
final random = Random();
−
 
 
−
// 100 números aleatorios entre 1 y 100.
 
−
final numerosAleatorios = List<int>.generate(
 
−
100,
 
−
(_) => random.nextInt(100) + 1,
 
−
);
 
  
−
print(numerosAleatorios);
+
// 100 números aleatorios entre 1 y 100.
−
 
+
final numerosAleatorios = List<int>.generate(
−
// Números desde 1 hasta 100.
+
100,
−
// Lista de longitud fija.
+
(_) => random.nextInt(100) + 1,
−
final numerosSecuenciales =
+
);
−
List<int>.generate(
 
−
100,
 
−
(posicion) => posicion + 1,
 
−
growable: false,
 
−
);
 
  
−
print(numerosSecuenciales);
+
print(numerosAleatorios);
  
−
// Cuadrados desde 1 hasta numero.
+
// Números desde 1 hasta 100.
−
// La lista permite añadir elementos.
+
// Lista de longitud fija.
−
const numero = 10;
+
final numerosSecuenciales = List<int>.generate(
 +
100,
 +
(posicion) => posicion + 1,
 +
growable: false,
 +
);
  
−
final numerosAlCuadrado =
+
print(numerosSecuenciales);
−
List<int>.generate(
 
−
numero,
 
−
(posicion) {
 
−
final valor = posicion + 1;
 
  
−
```
+
// Cuadrados desde 1 hasta numero.
−
  return valor * valor;
+
// La lista permite añadir elementos.
−
},
+
const numero = 10;
−
growable: true,
 
−
```
 
  
−
);
+
final numerosAlCuadrado = List<int>.generate(
 +
numero,
 +
(posicion) {
 +
final valor = posicion + 1;
  
−
print(numerosAlCuadrado);
+
return valor * valor;
 +
},
 +
growable: true,
 +
);
  
−
numerosAlCuadrado.add(121);
+
print(numerosAlCuadrado);
  
−
print(numerosAlCuadrado);
+
numerosAlCuadrado.add(121);
−
} </syntaxhighlight>
 
  
−
 
+
print(numerosAlCuadrado);
−
 
 
−
 
 
−
<br />
 
−
 
 
−
[https://wiki.cifprodolfoucha.es/index.php?title=Programaci%C3%B3n_de_dispositivos_m%C3%B3viles_con_FLUTTER#Unidad_2:_Lenguaje_DART Enlace a la página principal de la UD2]
 
−
 
 
−
[https://wiki.cifprodolfoucha.es/index.php?title=Programaci%C3%B3n_de_dispositivos_m%C3%B3viles_con_FLUTTER Enlace a la página principal del curso]
 
−
 
 
−
<br />
 
−
 
 
−
==Funciones flecha o Lambda==
 
−
 
 
−
* Son las '''arrow function''' o funciones '''lambda'''.
 
−
: Son funciones que retornan una expresión y que <u>no pueden tener bloque de código</u>.
 
−
: La expresión que se va a devolver va a continuación de '''=>'''.
 
−
: Viene a ser equivalente a '''return ??????''' aunque también se pueden emplear para ejecutar una instrucción cualquiera.
 
−
 
 
−
 
 
−
: Su sintaxis sería la siguiente:
 
−
::<syntaxhighlight lang="java" enclose="div" highlight="1,5" >
 
−
return_type function_name(arguments) => expression;
 
−
</syntaxhighlight>
 
−
 
 
−
 
 
−
 
 
−
: Por ejemplo:
 
−
:<syntaxhighlight lang="java" enclose="div" highlight="1,5" >
 
−
double sumar(double a, double b) => a+b;
 
−
 
 
−
void main() {
 
−
 
 
−
  print(sumar(10.22,22.34)); 
 
−
}
 
−
</syntaxhighlight>
 
−
 
 
−
 
 
−
 
 
−
* Si queremos que ejecuta una instrucción cualquiera:
 
−
:<syntaxhighlight lang="java" enclose="div" highlight="1" >
 
−
void imprimirMediaNumero({required int num1, required int num2}) => print((num1+num2)/2);
 
−
 
 
−
 
 
−
void main() {
 
−
 
 
−
  imprimirMediaNumero(num1: 10, num2: 15);
 
 
}
 
}
−
</syntaxhighlight>
 
−
 
−
 
−
 
−
<br />
 
−
 
−
==Funciones anónimas==
 
−
* Son funciones que no tienen nombre asociado.
 
−
: Es decir, son funciones que se emplean dentro de la llamada a un método y en vez de llamar a una función previamente definida por nosotros, ejecutamos una o varias instrucciones que conformaría la función si la tuviéramos definida.
 
−
 
−
* Veamos un ejemplo con el [https://api.dart.dev/stable/1.10.1/dart-core/List/forEach.html método forEach asociado a una lista].
 
−
: Si os fijáis en la definición, el método forEach espera recibir una función que no devuelve nada (void) y que tiene un parámetro de tipo E.
 
−
: El tipo va a depender del tipo de dato de los elementos que conforman la lista.
 
−
: Veamos en el ejemplo que vimos antes que tipo de datos va a ser E:
 
−
[[Imagen:Flutter_dart_fuhciones_1.JPG|800px|center]]
 
−
 
−
: Al tener un conjunto de datos enteros, espera ejecutar una función a la que se le va a pasar cada uno de los elementos de la lista, por lo que espera un entero.
 
−
: La implementación de la funcuón anónima sería la siguiente:
 
−
:<syntaxhighlight lang="java" enclose="div" highlight="5" >
 
−
void main() {
 
−
 
−
  List<int> lista = [1,2,3,4,5,6];
 
−
 
−
  lista.forEach((elemento) { // Código de la función
 
−
                          });
 
−
 
 
−
}
 
−
</syntaxhighlight>
 
−
: Hasta este punto, lo <u>importante es el parámetro '''elemento'''</u> el cual va a representar cada uno de los elementos de la lista.
 
−
: Es decir, Dart va a ejecutar el código que se encuentra entre llaves, y dentro del código vamos a tener acceso al elemento de la lista. Recordar que el código de la función lo va a ejecutar '''por cada elemento de la lista'''.
 
−
 
−
* Ahora dentro del código vamos a poder hacer lo que queramos (recordar que se ejecuta por cada elemento de la lista):
 
−
:<syntaxhighlight lang="java" enclose="div" highlight="6" >
 
−
void main() {
 
−
 
−
  List<int> lista = [1,2,3,4,5,6];
 
−
 
−
  lista.forEach((elemento) { // Código de la función
 
−
                            print('Accediendo al elemento $elemento');
 
−
                          });
 
−
}
 
−
</syntaxhighlight>
 
−
 
−
: Esta forma de definir funciones se usa habitualmente en Flutter.
 
−
 
−
* Como ya vimos antes las <u>funciones arrows</u>, podemos modificar el código de la función anónima en el caso de ejecutar una única sentencia.
 
−
:<syntaxhighlight lang="java" enclose="div" highlight="5" >
 
−
void main() {
 
−
 
−
  List<int> lista = [1,2,3,4,5,6];
 
−
 
−
  lista.forEach((elemento) => print('Accediendo al elemento $elemento'));
 
−
}
 
−
</syntaxhighlight>
 
−
: <u>'''Nota importante:'''</u>Fijarse que en la función anónima estamos empleando la función arrow (=>) por lo que indicamos que sólo vamos a ejecutar una sentencia.
 
−
: Si quisiéramos ejecutar más de una sentencia tendríamos que quitar la función arrow y escribir entre llaves { } el conjunto de instrucciones
 
−
 
−
 
−
 
−
 
−
* A continuación muestro otras formas de ejecutar el bucle forEach:
 
−
:<syntaxhighlight lang="java" enclose="div" highlight="" >
 
−
void gestionarElemLista(int elem){
 
−
 
 
−
  print('Elemento de la lista: $elem');
 
−
}
 
−
 
−
void function; gestionarElemLista2() {
 
−
  return (item) {
 
−
    print("The number is $item");
 
−
  };
 
−
}
 
−
 
−
void gestionarElemLista3(int elemLista){
 
−
  print('El número es $elemLista');
 
−
}
 
−
 
−
 
−
void main() {
 
−
 
−
  List<int> lista = [1,2,3,4,5,6];
 
−
 
−
  lista.forEach((elemento) => gestionarElemLista(elemento));
 
−
  lista.forEach(gestionarElemLista2());
 
−
 
−
  lista.forEach((elemento) => print('Función anónima : Elemento de la lista: $elemento'));
 
−
 
−
  lista.forEach(gestionarElemLista3);    // NO PONEMOS PARÉNTESIS
 
−
 
−
 
 
−
}
 
−
 
−
</syntaxhighlight>
 
−
 
−
 
−
<br />
 
−
 
−
: Veamos otros ejemplos de forEach aplicada a otras estructuras de datos....
 
−
 
−
* '''forEach en Mapas''':
 
−
:<syntaxhighlight lang="java" enclose="div" highlight="12" >
 
−
void main() {
 
−
 
−
  Map<String,double>mapa = {
 
−
    'base' : 1.84,
 
−
    'alero' : 1.95,
 
−
    'pivot' : 2.10,
 
−
    'escola' : 1.90
 
−
    };
 
−
 
 
−
  mapa.values.forEach((valor) => print('Valor del mapa: $valor'));  // Accedemos a los valores
 
−
  mapa.keys.forEach((key) => print('La clave $key')); // Accedemos a las claves
 
−
  mapa.forEach((key,valor) => print('La clave $key tiene el valor $valor')); 
 
−
}
 
−
</syntaxhighlight>
 
−
: Fijarse como la función anónima del forEach aplicado al Map espera recibir dos parámetros: uno representa la clave y otro el valor asociado a dicha clave.
 
−
 
−
 
−
 
−
<br />
 
−
* '''forEach en Conjuntos''':
 
−
:<syntaxhighlight lang="java" enclose="div" highlight="12" >
 
−
void main() {
 
−
 
−
  var conjunto = {'Angel','Luis','Ana','María'};
 
−
 
 
−
  conjunto.forEach((valor) => print('El elemento de la lista: $valor'));
 
−
 
−
}
 
−
</syntaxhighlight>
 
−
 
−
 
−
 
−
<br />
 
−
 
−
* Cuando empleamos los métodos que esperan una función como parámetro (como por ejemplo forEach), podemos definir la función sin emplear una función anónima de la forma:
 
−
:<syntaxhighlight lang="java" enclose="div" highlight="" >
 
−
Set<String> conjunto = {'uno','dos','tres'};
 
−
  conjunto.forEach(recorrerConjunto);
 
−
}
 
−
void recorrerConjunto(String n){
 
−
  print(n);
 
−
}
 
−
</syntaxhighlight>
 
−
 
−
 
−
: Como veis, en el método forEach indicamos <u>'''sólo el nombre de la función'''</u> y defino la función con el parámetro que necesita el método forEach.
 
−
 
−
 
−
 
−
<br />
 
−
 
−
==Método map aplicado a List y Set==
 
−
 
−
* Más información en https://api.dart.dev/stable/3.1.2/dart-core/Iterable/map.html
 
−
 
−
 
−
* Esta función es muy útil en Flutter, ya que vamos a generar un conjunto de Widget en base a los datos que haya en una lista o conjunto.
 
−
: Lo que hace esta función es, <u>por cada uno de los elementos de la lista/conjunto</u> crear un nuevo objeto que irá añdiéndolos a un objeto Iterable. Al finalizar estarán todos los nuevos objetos creados en dicho objeto Iterable. Lo que se hace normalmente es llamar al método '''toList()''' para convertir dicho objeto Iterable en una lista.
 
−
: Como resultado, tendremos una nueva lista con una serie de nuevos objetos basados en los datos de la lista inicial.
 
−
 
−
* Veamos un ejemplo:
 
−
:<syntaxhighlight lang="java" enclose="div" highlight="" >
 
−
  Map<String,String> mapa={};
 
−
 
−
  mapa.addAll({'nombre' : 'angel', 'apellido1' : 'fernandez', 'apellido2' : 'gonzalez'});
 
−
  List<String> lista = mapa.entries.map((e) => ('HOLA:${e.value}') ).toList();  // Creamos por cada elemento del conjunto una cadena con el formato 'HOLA:elem_conjunto'. Convertimos todo a una lista.
 
−
  print(lista);
 
−
</syntaxhighlight>
 
−
 
−
 
−
 
−
 
−
 
−
 
−
 
−
<br />
 
−
 
−
==Ejercicios propuestos==
 
−
 
−
'''Ejercicio 1:'''
 
−
 
−
Crea una función que espere recibir en cualquier orden un número y una lista y devuelva el valor de la lista que se encuentra en la posición enviada.
 
−
: Si no se envía posición debe devolver el primer elemento de la lista y la lista siempre debe ser enviada.
 
−
: Si la lista enviada no tiene datos debe devolver la cadena 'Sin datos' (emplea algún método de la clase List que te sirva para comprobar si está vacía la lista).
 
−
: Si la posición del elemento de la lista es superior al número de elementos de la lista, debe devolver la cadena 'Indice fuera de rango'.
 
−
 
−
 
−
'''Ejercicio 2:'''
 
−
Crea un mapa de datos en los que se guarde como valor clave un índice y como dato, un precio.
 
−
 
−
:* Define inicialmente cuatro entradas del mapa.
 
−
:* Añade dos nuevos elementos al mapa.
 
−
:* Borra el último elemento del mapa.
 
−
:* Recorre los elementos del mapa empleando una función anónima. Dicha función debe mostrar la clave y el precio de todos los platos que valgan menos de 5 euros.
 
−
:* Crea una función de nombre getNumPlatosMasCaros al que se le pase como parámetros en cualquier posición un mapa y un precio (no deben admitir valores nulos).
 
−
:: Dicha función debe devolver cuantos platos tienen un precio superior al enviado.
 
−
:: Tanto el precio  como el mapa deben ser enviados y en cualquier orden.
 
−
:: Llama a dicha función para comprobar que funciona.
 
−
 
−
 
−
 
−
'''Ejercicio 3:'''
 
−
En este ejercicio vas a probar a emplear otro método que permite emplear funciones anónimas, como es el [https://api.flutter.dev/flutter/dart-core/Iterable/where.html método where].
 
−
Veamos en el siguiente volcado, qué necesitamos para usar dicho método, sobre un conjunto (Set).
 
−
Los elementos del conjunto son de tipo String.
 
−
[[Imagen:Flutter_dart_fuhciones_2.JPG|500px|center]]
 
−
 
−
: En la imagen anterior:
 
−
:* Podemos comprobar como espera una función que devuelva un boolean: '''bool Function'''
 
−
:* Dicha función va a hacer uso de un parámetro de tipo String (recordar que la imagen anterior está aplicada sobre un Set de elementos de tipo String). Quiero esto decir que la función se va a ejecutar por cada elemento del conjunto y el parámetro será cada uno de esos elementos.
 
−
:* En el cuerpo de la función escribiremos el código y haremos un return de una expresión que devueva un booleano. Si la función puede ser implementada con una única instrucción, podemos emplear una función flecha (como vimos antes).
 
−
:* Aquellos elementos que satisfagan la condición, será de vueltos en forma de '[https://api.flutter.dev/flutter/dart-core/Iterable-class.html conjunto iterable]': '''Iterable<String>'''.
 
−
 
−
: Por lo tanto vamos a poder recorrer dichos elementos empleando el método iterator, como ya [https://wiki.cifprodolfoucha.es/index.php?title=Flutter_DART_variables_-_tipos_de_datos#Listas vimos con las listas y conjuntos] o bien podemos hacer uso del método forEach como vimos anteriormente.
 
−
 
−
Teniendo en cuenta todo lo anterior, crea un conjunto de nombre equipo que tenga los valores 'Base','Alero','Pivot','Escolta'.
 
−
Crea un método que reciba como parámetro el conjunto y la cadena a buscar. Emplea el método where y muestra aquellos elementos del conjunto que tengan como parte de su valor una cadena a buscar.
 
−
Busca por la cadena: as
 
−
Busca por la cadena: s
 
−
 
−
 
−
 
−
'''Ejercicio 4:'''
 
−
En base a lo aprendido en el ejercicio anterior, crea una lista de números con los siguintes datos: 10.0, 11.22, 15.0, 7.0, 3.44
 
−
Busca dentro de la clase List, qué método podrías emplear para que dado un número, comprobar si todos los elementos de la lista son mayores a dicho número.
 
−
Crea una función de nombre 'sonMayores' a la que se le pasen dos parámetros en cualquier orden. El primer parámetro es el número empleado para comprobar que todos los elementos de la lista son mayores a él. Si no se envía se debe emplear el valor 0 por defecto. El segundo parámetro es una lista.
 
−
Esta función debe devolver la cadena SI / NO en función si todos los elementos de la lista son mayores al número empleado como parámetro.
 
−
Llama a dicha función con el valor 2 y con el valor 12.
 
−
Imprime la cadena: Todos los números de la lista son mayores a XX: YY siendo XX el número y YY la cadena SI / NO.
 
−
 
−
 
−
 
−
'''Ejercicio 5:'''
 
−
La clase List tiene un [https://api.dart.dev/stable/2.13.4/dart-core/List/List.generate.html método generate].
 
−
Emplea dicho método para generar una lista de 100 números aleatorios.
 
−
 
−
Variación 1: Haz que empiece en el número 1 y acabe en el 100 y que no se puedan añadir nuevos elementos.
 
−
Variación 2: Crea una lista en la que dado un número se guarde en la lista el cuadrado de todos los números desde 1 hasta el mismo, y que se puedan añadir nuevos elementos.
 
−
 
−
 
−
 
−
'''Ejercicios propuestos:'''
 
−
Comprueba que métodos dispones en las clase List, Map, Set que se puedan emplear con funciones anónimas y haz un ejemplo de cada uno de ellos.
 
−
 
−
 
−
 
−
 
−
 
−
<br />
 
−
===Soluciones Ejercicios propuestos===
 
−
 
−
'''Solución Ejercicio 1:'''
 
−
Crea una función que espere recibir en calquier orden un número y una lista y devuelva el valor de la lista que se encuentra en la posición enviada.
 
−
: Si no se envía posición debe devolver el primer elemento de la lista y la lista siempre debe ser enviada.
 
−
: Si la lista enviada no tiene datos debe devolver la cadena 'Sin datos' (emplea algún método de la clase List que te sirva para comprobar si está vacía la lista).
 
−
: Si la posición del elemento de la lista es superior al número de elementos de la lista, debe devolver la cadena 'Indice fuera de rango'.
 
−
 
−
:<syntaxhighlight lang="java" enclose="div" highlight="" >
 
−
String devolverElementoLista(
 
−
  {int pos=0, required List listaRecibir})
 
−
{
 
−
  if(listaRecibir.isEmpty) return 'Sin datos';
 
−
  if(pos >= listaRecibir.length) return 'Indice fuera de rango.';
 
−
 
 
−
  return listaRecibir[pos];
 
−
}
 
−
 
−
void main() {
 
−
 
−
  final lista = ['Uno','Dos','Tres','Cuatro'];
 
−
 
 
−
  print(devolverElementoLista(listaRecibir: lista));
 
−
  print(devolverElementoLista(listaRecibir: lista,pos: 2));
 
−
  print(devolverElementoLista(listaRecibir: lista,pos: 4));
 
−
 
 
−
 
−
}
 
−
 
−
</syntaxhighlight>
 
−
 
−
 
−
'''Solución Ejercicio 2:'''
 
−
Crea un mapa de datos en los que se guarde como valor clave un índice y como dato, un precio.
 
−
 
−
:* Define inicialmente cuatro entradas del mapa.
 
−
:* Añade dos nuevos elementos al mapa.
 
−
:* Borra el último elemento del mapa.
 
−
:* Recorre los elementos del mapa empleando una función anónima. Dicha función debe mostrar la clave y el precio de todos los platos que valgan menos de 5 euros.
 
−
:* Crea una función de nombre getNumPlatosMasCaros al que se le pase como parámetros en cualquier posición un mapa y un precio (no deben admitir valores nulos).
 
−
:: Dicha función debe devolver cuantos platos tienen un precio superior al enviado.
 
−
:: Tanto el precio  como el mapa deben ser enviados y en cualquier orden.
 
−
:: Llama a dicha función para comprobar que funciona.
 
−
:<syntaxhighlight lang="java" enclose="div" highlight="" >
 
−
 
−
int getNumPlatosMasCaros({required Map mapa, required double precio}){
 
−
 
 
−
  var contador=0;
 
−
  mapa.values.forEach((preciosmapa) => preciosmapa > precio ? contador++ : 0);
 
−
 
 
−
  return contador;
 
−
 
 
−
}
 
−
 
−
void main() {
 
−
 
−
  final precios = <int,double>{
 
−
    1 : 10.34,
 
−
    2 : 3.24,
 
−
    3 : 24.99,
 
−
    4 : 17.35
 
−
  }; 
 
−
 
−
  precios.addAll({5 : 9.23, 6: 2.22});  // Añade dos nuevos elememtos al mapa
 
−
  print(precios);
 
−
 
 
−
  int key = precios.keys.elementAt(precios.length-1); 
 
−
  precios.remove(key);  // Borra el último elemento del mapa
 
−
 
 
−
  precios.forEach((clave,valor) => valor < 5 ? print('La clave $clave tiene un precio de $valor') : '');
 
−
 
 
−
  print('Número de platos mayores a 10 euros:${getNumPlatosMasCaros(mapa: precios, precio: 10)}');
 
−
 
 
−
}
 
−
 
 
</syntaxhighlight>
 
</syntaxhighlight>
−
 
−
 
−
 
−
'''Solución Ejercicio 3:'''
 
−
Crea un método que reciba como parámetro el conjunto y la cadena a buscar. Emplea el método where y muestra aquellos elementos del conjunto que tengan como parte de su valor una cadena a buscar.
 
−
Busca por la cadena: as
 
−
Busca por la cadena: s
 
−
 
−
:<syntaxhighlight lang="java" enclose="div" highlight="" >
 
−
void cadenaBuscar(Set conjunto, String cadena){
 
−
 
−
  conjunto.where((elemento) => elemento.indexOf(cadenaBusqueda) > 0)
 
−
    .forEach((elemento) => print('Encontrado:$elemento'));
 
−
 
−
}
 
−
void main() {
 
−
 
−
  final equipo = {'Base','Alero','Pivot','Escolta'};
 
−
  var cadenaBusqueda = 'as';
 
−
 
 
−
  print('Cadena de búsqueda:$cadenaBusqueda');
 
−
  cadenaBuscar(equipo,cadenaBusqueda);
 
−
 
−
  cadenaBusqueda='s';
 
−
  print('Cadena de búsqueda:$cadenaBusqueda');
 
−
  cadenaBuscar(equipo,cadenaBusqueda);
 
−
 
 
−
}
 
−
</syntaxhighlight>
 
−
 
−
 
−
 
−
'''Solución Ejercicio 4:'''
 
−
En base a lo aprendido en el ejercicio anterior, crea una lista de números con los siguintes datos: 10.0, 11.22, 15.0, 7.0, 3.44
 
−
Busca dentro de la clase List, qué método podrías emplear para que dado un número, comprobar si todos los elementos de la lista son mayores a dicho número.
 
−
Crea una función de nombre 'sonMayores' a la que se le pasen dos parámetros en cualquier orden. El primer parámetro es el número empleado para comprobar que todos los elementos de la lista son mayores a él. Si no se envía se debe emplear el valor 0 por defecto. El segundo parámetro es una lista.
 
−
Esta función debe devolver la cadena SI / NO en función si todos los elementos de la lista son mayores al número empleado como parámetro.
 
−
Llama a dicha función con el valor 2 y con el valor 12.
 
−
Imprime la cadena: Todos los números de la lista son mayores a XX: YY siendo XX el número y YY la cadena SI / NO.
 
−
 
−
:<syntaxhighlight lang="java" enclose="div" highlight="" >
 
−
String sonMayores({numero = 0, required List lista}) => lista.every((elem) => elem > numero) ? 'SI' : 'NO'
 
−
 
−
 
−
 
−
void main() {
 
−
 
−
  final listaNumeros = [10.0, 11.22, 15.0, 7.0, 3.44];
 
−
 
 
−
  var numeroReferencia = 2;
 
−
 
 
−
  print('Todos los números de la lista son mayores a $numeroReferencia: ${sonMayores(numero: numeroReferencia, lista : listaNumeros)}');
 
−
 
−
  numeroReferencia = 12;
 
−
  print('Todos los números de la lista son mayores a $numeroReferencia: ${sonMayores(numero: numeroReferencia, lista : listaNumeros)}');
 
−
 
 
−
}
 
−
 
−
</syntaxhighlight>
 
−
 
−
 
−
 
−
 
−
'''Solución Ejercicio 5:'''
 
−
La clase List tiene un [https://api.dart.dev/stable/2.13.4/dart-core/List/List.generate.html método generate].
 
−
Emplea dicho método para generar una lista de 100 números aleatorios.
 
−
 
−
Variación 1: Haz que empiece en el número 1 y acabe en el 100 y que no se puedan añadir nuevos elementos.
 
−
Variación 2: Crea una lista en la que dado un número se guarde en la lista el cuadrado de todos los números desde 0 hasta el mismo, y que se puedan añadir nuevos elementos.
 
−
 
−
:<syntaxhighlight lang="java" enclose="div" highlight="" >
 
−
 
−
void main() {
 
−
 
−
  var numerosSecuenciales = List<int>.generate(100,(posicion) => posicion);
 
−
  print(numerosSecuenciales);
 
−
 
 
−
  var numerosSecuencialesEmpiezanUno = List<int>.generate(100,(posicion) => posicion+1, growable: false);
 
−
  print(numerosSecuencialesEmpiezanUno);
 
−
 
 
−
  const numero = 10;
 
−
  var numerosAlCuadrado = List<int>.generate(numero,(posicion) => posicion*posicion, growable: true);
 
−
  print(numerosAlCuadrado);
 
−
 
 
−
 
 
−
}
 
−
</syntaxhighlight>
 
−
 
  
  
Línea 1743: Línea 1182:
 
[https://wiki.cifprodolfoucha.es/index.php?title=Programaci%C3%B3n_de_dispositivos_m%C3%B3viles_con_FLUTTER Enlace a la página principal del curso]
 
[https://wiki.cifprodolfoucha.es/index.php?title=Programaci%C3%B3n_de_dispositivos_m%C3%B3viles_con_FLUTTER Enlace a la página principal del curso]
  
−
 
+
<br />
−
 
+
```
−
 
 
−
<br> -- [[Usuario:angelfg|Ángel D. Fernández González]] -- (2021).
 

Revisión actual del 07:34 24 sep 2026

Introducción

  • En Dart, las funciones permiten agrupar código que puede ejecutarse desde diferentes partes de un programa.
 : Como este curso está orientado a alumnado que ya sabe programar en algún lenguaje, no profundizaremos en los conceptos generales de las funciones, sino en las características específicas que ofrece Dart.
  • Es recomendable indicar el tipo de los parámetros que recibe una función y el tipo del dato que devuelve.
  • Veamos un ejemplo de función con parámetros:
double sumarValores(double val1, double val2) {
return val1 + val2;
}

void main() {
final num1 = 10.32;
final num2 = 1.35;

print(sumarValores(num1, num2));
}


Paso de parámetros

  • Al igual que en otros lenguajes, podemos pasar datos a las funciones empleando parámetros.
Como ya vimos anteriormente, podemos definir parámetros que admitan valores nulos utilizando los tipos nullable, como por ejemplo String?, int? o double?.


Paso por valor

  • En Dart, los argumentos de una función se pasan por valor.
Las variables de Dart contienen referencias a objetos. Cuando enviamos una variable como argumento de una función, se copia el valor almacenado en dicha variable.
Si dicho valor es una referencia a un objeto, se copia la referencia. Por tanto, tanto la variable original como el parámetro pueden hacer referencia al mismo objeto.
Esto provoca dos comportamientos que debemos diferenciar:
  • Si reasignamos el parámetro dentro de la función, no modificamos la variable utilizada en la llamada.
  • Si utilizamos la referencia recibida para modificar el estado de un objeto mutable, el cambio será visible fuera de la función, ya que ambas referencias permiten acceder al mismo objeto.
class Pelota {
  double? peso;
  String? id;
}

void modificarValores(
  Pelota pelota,
  int valor,
  String cadena,
) {
  valor = 10;
  cadena = 'NUEVA CADENA';

  pelota.peso = 100.2;
  pelota.id = 'P2';
}

void main() {
  var valorPrueba = 5;
  var cadena = 'VIEJA CADENA';

  final pelota = Pelota();

  pelota.id = 'P1';
  pelota.peso = 50.34;

  modificarValores(
    pelota,
    valorPrueba,
    cadena,
  );

  print('Valor numérico: $valorPrueba');
  print('Cadena: $cadena');
  print('Objeto: ${pelota.id} -- ${pelota.peso}');
}


Después de ejecutar la función:
  • valorPrueba sigue valiendo 5.
  • cadena sigue conteniendo 'VIEJA CADENA'.
  • Las propiedades del objeto pelota sí han cambiado.
Por tanto, no es correcto decir que Dart pasa unos tipos por valor y otros por referencia. Todos los argumentos se pasan por valor; cuando trabajamos con objetos, el valor copiado es una referencia al objeto.


Parámetros opcionales posicionales


  • Podemos definir parámetros posicionales opcionales escribiéndolos entre corchetes [ ].
void imprimirMensaje([String mensaje = 'Nada enviado']) {
print(mensaje);
}

void main() {
imprimirMensaje();
imprimirMensaje('Nuevo mensaje');
}
En la primera llamada no enviamos ningún valor, por lo que el parámetro utiliza su valor por defecto.
  • Si el parámetro admite valores nulos, no es necesario establecer un valor por defecto:
void imprimirMensaje([String? mensaje]) {
print(mensaje);
}

void main() {
imprimirMensaje();
imprimirMensaje('Nuevo mensaje');
}
Si no enviamos ningún valor, mensaje tendrá el valor null.
  • Si una función tiene parámetros posicionales obligatorios y opcionales, los opcionales deben aparecer al final:
void imprimirMensaje(int numero, [String? mensaje]) {
print('$numero - $mensaje');
}


Parámetros con nombre

  • Dart permite definir parámetros con nombre.
Para ello se escriben los parámetros entre llaves { }.
void imprimirMensaje({
String? mensaje,
}) {
print(mensaje);
}
  • Al realizar la llamada indicamos el nombre del parámetro:
void main() {
imprimirMensaje(
mensaje: 'Hola',
);
}
  • Una ventaja de los parámetros con nombre es que podemos indicar los argumentos por su nombre, haciendo las llamadas más fáciles de leer.


Parámetros con nombre opcionales

  • Los parámetros con nombre son opcionales por defecto.
Si el parámetro puede valer null, podemos declararlo como nullable:
void imprimirMensaje1({
String? mensaje,
}) {
print(mensaje);
}

void main() {
imprimirMensaje1();
imprimirMensaje1(
mensaje: 'Hola',
);
}
  • Otra posibilidad es proporcionar un valor por defecto:
void imprimirMensaje2({
String mensaje = 'Valor por defecto',
}) {
print(mensaje);
}

void main() {
imprimirMensaje2();

imprimirMensaje2(
mensaje: 'Nuevo mensaje',
);
}


Parámetros con nombre obligatorios

  • Podemos indicar que un parámetro con nombre es obligatorio utilizando la palabra clave required.
void imprimirMensaje({
required String mensaje,
}) {
print(mensaje);
}

void main() {
imprimirMensaje(
mensaje: 'Mensaje',
);
}
En este caso estamos obligados a enviar el argumento correspondiente a mensaje.
Como el parámetro es obligatorio y su tipo es String, no necesitamos asignarle un valor por defecto ni permitir que sea null.


Combinación de parámetros posicionales y con nombre

  • Podemos combinar parámetros posicionales y parámetros con nombre.
Los parámetros posicionales se escriben antes que los parámetros con nombre:
void imprimirMensaje(
  int numero, {
    String? mensaje,
  }
) {
  print(
    'El número es $numero y el mensaje es $mensaje',
  );
}

void main() {
  imprimirMensaje(
    10,
    mensaje: 'Mensaje',
  );
}


Funciones flecha o arrow functions

  • Cuando una función está formada por una única expresión, podemos utilizar la sintaxis de función flecha mediante el operador =>.
Por ejemplo, la siguiente función:
double sumar(double a, double b) {
return a + b;
}
puede escribirse como:
double sumar(double a, double b) => a + b;
  • Después de => se escribe una expresión.
El resultado de dicha expresión será el valor devuelto por la función cuando esta tenga un tipo de retorno distinto de void.
double calcularMedia(
double num1,
double num2,
) =>
(num1 + num2) / 2;
  • También podemos emplearla con una expresión que no produzca un valor útil, como una llamada a print:
void imprimirMediaNumero({
required int num1,
required int num2,
}) =>
print((num1 + num2) / 2);

void main() {
imprimirMediaNumero(
num1: 10,
num2: 15,
);
}
  • Si necesitamos ejecutar varias instrucciones, debemos emplear un bloque de código con llaves:
void mostrarDatos(int numero) {
print('Número recibido:');
print(numero);
}


Funciones anónimas

  • Una función anónima es una función que no tiene un nombre asociado.
Las funciones anónimas son especialmente útiles como argumentos de métodos que esperan recibir otra función.
Este tipo de métodos aparece frecuentemente cuando trabajamos con colecciones y también en Flutter mediante callbacks.
  • Una función anónima puede tener un bloque de código:
(elemento) {
print(elemento);
}
  • Si únicamente necesitamos una expresión, podemos emplear la sintaxis flecha:
(elemento) => print(elemento)


Funciones anónimas y forEach

  • El método forEach de un Iterable espera recibir una función que será ejecutada una vez por cada elemento.
Por ejemplo:
void main() {
final lista = <int>[1, 2, 3, 4, 5, 6];

lista.forEach((elemento) {
print('Accediendo al elemento $elemento');
});
}
El parámetro elemento representa, en cada ejecución, uno de los elementos de la lista.
  • Podemos expresar lo mismo mediante una función flecha:
void main() {
final lista = <int>[1, 2, 3, 4, 5, 6];

lista.forEach(
(elemento) => print(
'Accediendo al elemento $elemento',
),
);
}

Nota importante:

Aunque estas formas son válidas y sirven para comprender el funcionamiento de las funciones anónimas, para realizar un recorrido sencillo de un Iterable, Dart recomienda normalmente utilizar for...in en lugar de forEach con una función anónima.
Por ejemplo:
void main() {
final lista = <int>[1, 2, 3, 4, 5, 6];

for (final elemento in lista) {
print(
'Accediendo al elemento $elemento',
);
}
}


Pasar una función existente como parámetro

  • Cuando un método espera una función como parámetro, no siempre tenemos que crear una función anónima.
Podemos pasar una función que ya esté definida:
void recorrerConjunto(String elemento) {
print(elemento);
}

void main() {
final conjunto = <String>{
'uno',
'dos',
'tres',
};

conjunto.forEach(recorrerConjunto);
}
Fijarse en que escribimos:
conjunto.forEach(recorrerConjunto);
y no:
conjunto.forEach(recorrerConjunto());
No queremos ejecutar recorrerConjunto en ese momento. Queremos proporcionar la función a forEach para que sea este método quien la ejecute posteriormente una vez por cada elemento.
  • La función que enviemos debe ser compatible con el tipo de función que espera el método.
En este ejemplo, el conjunto contiene elementos de tipo String, por lo que la función recibe un String y devuelve void:
void recorrerConjunto(String elemento) {
print(elemento);
}


Tear-offs

  • Cuando hacemos referencia a una función o método sin utilizar los paréntesis de llamada, Dart crea lo que se denomina un tear-off.
Por ejemplo:
conjunto.forEach(recorrerConjunto);
recorrerConjunto representa la función que queremos proporcionar a forEach.
  • Dart recomienda no crear una función anónima innecesaria cuando podemos pasar directamente una función existente.
Por tanto, en lugar de:
lista.forEach(
(elemento) => gestionarElemento(elemento),
);
es preferible:
lista.forEach(gestionarElemento);
  • Incluso podemos proporcionar directamente una función existente de Dart si es compatible con los parámetros esperados:
lista.forEach(print);


Diferentes formas de proporcionar una función a forEach

  • Veamos las diferentes posibilidades:
void gestionarElemento(int elemento) {
print('Elemento: $elemento');
}

void main() {
final lista = <int>[1, 2, 3, 4, 5, 6];

// Función anónima con bloque.
lista.forEach((elemento) {
print('Función anónima: $elemento');
});

// Función anónima flecha.
lista.forEach(
(elemento) =>
print('Función flecha: $elemento'),
);

// Función previamente definida.
lista.forEach(gestionarElemento);

// Función existente compatible.
lista.forEach(print);
}
Las dos primeras formas son útiles para comprender cómo funcionan las funciones anónimas.
Sin embargo, si únicamente queremos recorrer un Iterable, normalmente emplearemos:
for (final elemento in lista) {
print(elemento);
}
Si queremos ejecutar exactamente una función existente para cada elemento, forEach es apropiado:
lista.forEach(gestionarElemento);
lista.forEach(print);


Funciones que devuelven funciones

  • En Dart, las funciones son objetos. Esto significa que una función también puede devolver otra función.
Veamos un ejemplo:
void Function(int) crearFuncion() {
return (int elemento) {
print('Número: $elemento');
};
}

void main() {
final lista = <int>[1, 2, 3];

lista.forEach(crearFuncion());
}
En este caso ocurre algo diferente al ejemplo anterior.
Primero se ejecuta:
crearFuncion()
Esta función devuelve otra función compatible con la función que espera forEach.
Por ese motivo, en este caso sí aparecen los paréntesis después de crearFuncion.
Este tipo de funciones recibe el nombre de funciones de orden superior. También están relacionadas con el concepto de closures, que veremos cuando sea necesario.


forEach en mapas

  • Los objetos de tipo Map también disponen del método forEach.
En este caso, la función recibe dos parámetros:
  • La clave.
  • El valor asociado a dicha clave.
void main() {
final mapa = <String, double>{
'base': 1.84,
'alero': 1.95,
'pivot': 2.10,
'escolta': 1.90,
};

mapa.forEach((clave, valor) {
print(
'La clave $clave tiene el valor $valor',
);
});
}
En el caso de Map.forEach, el empleo de una función anónima es totalmente apropiado.
  • Si queremos recorrer solamente las claves o solamente los valores, podemos emplear for...in:
void main() {
final mapa = <String, double>{
'base': 1.84,
'alero': 1.95,
'pivot': 2.10,
'escolta': 1.90,
};

for (final clave in mapa.keys) {
print('Clave: $clave');
}

for (final valor in mapa.values) {
print('Valor: $valor');
}
}


Recorrido de conjuntos

  • Los conjuntos (Set) son objetos Iterable, por lo que para un recorrido sencillo podemos utilizar for...in:
void main() {
final conjunto = <String>{
'Ángel',
'Luis',
'Ana',
'María',
};

for (final elemento in conjunto) {
print(elemento);
}
}
  • También podemos utilizar forEach si proporcionamos directamente una función existente:
void main() {
final conjunto = <String>{
'Ángel',
'Luis',
'Ana',
'María',
};

conjunto.forEach(print);
}


Método where

  • El método where permite filtrar los elementos de un Iterable.
Recibe como parámetro una función que debe devolver un valor booleano:
(elemento) => condición
Si la función devuelve true, el elemento formará parte del resultado.
Si devuelve false, el elemento será descartado.
  • Por ejemplo:
void main() {
final numeros = <int>[
1,
2,
3,
4,
5,
6,
];

final pares = numeros.where(
(numero) => numero.isEven,
);

print(pares);
}
where devuelve un Iterable.
  • Si queremos obtener una lista:
final pares = numeros
.where((numero) => numero.isEven)
.toList();
  • Si queremos obtener un conjunto:
final pares = numeros
.where((numero) => numero.isEven)
.toSet();


Método every

  • El método every permite comprobar si todos los elementos de un Iterable cumplen una determinada condición.
Devuelve un valor de tipo bool.
void main() {
final numeros = <int>[
10,
20,
30,
40,
];

final todosPositivos = numeros.every(
(numero) => numero > 0,
);

print(todosPositivos);
}
El resultado será true únicamente si todos los elementos cumplen la condición.


Método map aplicado a List y Set

  • El método map permite transformar los elementos de un Iterable.
Por cada elemento de la colección original se ejecuta una función que genera un nuevo valor.
Como resultado obtenemos un nuevo Iterable.
  • Por ejemplo:
void main() {
final numeros = <int>[
1,
2,
3,
4,
];

final cuadrados = numeros.map(
(numero) => numero * numero,
);

print(cuadrados);
}
  • Habitualmente convertiremos el resultado a una lista mediante toList():
final cuadrados = numeros
.map((numero) => numero * numero)
.toList();
  • Este método es especialmente útil en Flutter, ya que permite crear una colección de widgets a partir de una colección de datos.
Por ejemplo, conceptualmente podemos transformar una lista de cadenas en una lista de objetos:
void main() {
final nombres = <String>[
'Ana',
'Luis',
'María',
];

final mensajes = nombres
.map((nombre) => 'Hola $nombre')
.toList();

print(mensajes);
}
  • También podemos aplicar map sobre las entradas de un Map:
void main() {
final mapa = <String, String>{
'nombre': 'Ángel',
'apellido1': 'Fernández',
'apellido2': 'González',
};

final lista = mapa.entries
.map(
(entrada) => 'HOLA: ${entrada.value}',
)
.toList();

print(lista);
}


List.generate

  • La clase List dispone del constructor List.generate, que permite generar los elementos de una lista mediante una función.
La función recibe la posición que se está generando:
void main() {
final numeros = List<int>.generate(
5,
(posicion) => posicion,
);

print(numeros);
}
El resultado será:
[0, 1, 2, 3, 4]
  • Si queremos generar los números desde 1:
final numeros = List<int>.generate(
5,
(posicion) => posicion + 1,
);
  • Podemos indicar mediante growable: false que la lista tenga longitud fija:
final numeros = List<int>.generate(
5,
(posicion) => posicion + 1,
growable: false,
);

Importante:

Una lista con growable: false es una lista de longitud fija. Esto significa que no podemos añadir ni eliminar elementos.
Sin embargo, esto no significa que la lista sea inmutable. Podemos modificar el valor almacenado en una posición existente.


Ejercicios propuestos

Ejercicio 1:

Crea una función que espere recibir mediante parámetros con nombre una posición y una lista de cadenas, y devuelva el valor de la lista que se encuentra en la posición indicada.

  • La lista debe ser enviada obligatoriamente.
  • Si no se envía la posición, debe utilizarse la posición 0.
  • Si la lista no tiene elementos, debe devolver la cadena 'Sin datos'.
  • Si la posición es negativa o no existe en la lista, debe devolver la cadena 'Índice fuera de rango'.
  • Llama a la función empleando diferentes valores para comprobar su funcionamiento.


Ejercicio 2:

Crea un mapa de datos en el que se guarde como clave un índice entero y como valor un precio.

  • Define inicialmente cuatro entradas en el mapa.
  • Añade dos nuevas entradas.
  • Borra la última entrada introducida.
  • Recorre el mapa empleando forEach. La función debe mostrar la clave y el precio de todos los platos cuyo precio sea inferior a 5 euros.
  • Crea una función de nombre getNumPlatosMasCaros a la que se le pase mediante parámetros con nombre un mapa y un precio.
  • Los dos parámetros deben ser obligatorios y no admitir valores nulos.
  • La función debe devolver cuántos platos tienen un precio superior al indicado.
  • Emplea where para realizar el filtrado.
  • Llama a la función para comprobar que funciona.


Ejercicio 3:

Crea un conjunto de nombre equipo que contenga los valores:

Base
Alero
Pivot
Escolta

Crea una función que reciba como parámetros el conjunto y una cadena a buscar.

  • Emplea el método where.
  • La función debe mostrar los elementos del conjunto que contengan la cadena indicada.
  • Recorre el resultado empleando for...in.
  • Realiza una búsqueda con la cadena 'as'.
  • Realiza otra búsqueda con la cadena 's'.


Ejercicio 4:

Define una lista de números decimales con los siguientes valores:

10.0, 11.22, 15.0, 7.0, 3.44

Crea una función de nombre sonMayores:

  • Debe recibir mediante parámetros con nombre un número y una lista de números decimales.
  • La lista debe ser obligatoria.
  • Si no se envía el número, debe utilizarse el valor 0.
  • Emplea el método every para comprobar si todos los elementos de la lista son mayores que el número indicado.
  • La función debe devolver la cadena 'SI' o 'NO'.
  • Llama a la función empleando los valores 2 y 12.
  • Muestra una frase con el formato:
Todos los números de la lista son mayores a XX: YY
siendo XX el número utilizado e YY el resultado SI o NO.


Ejercicio 5:

Emplea List.generate para realizar los siguientes ejercicios:

  • Genera una lista de 100 números enteros aleatorios comprendidos entre 1 y 100. Emplea la clase Random.
  • Genera una lista con los números comprendidos entre 1 y 100 y haz que tenga longitud fija, de forma que no puedan añadirse ni eliminarse elementos.
  • Dado un número, genera una lista con los cuadrados de todos los números comprendidos entre 1 y dicho número. En este caso, la lista debe permitir añadir nuevos elementos.


Ejercicio adicional:

Investiga otros métodos disponibles en List, Set, Map o Iterable que reciban una función como parámetro.

  • Busca varios ejemplos.
  • Indica qué tipo de función espera cada método.
  • Realiza un pequeño ejemplo de uso.
  • Algunos métodos que puedes investigar son any, firstWhere, fold, removeWhere o updateAll.



Soluciones de los ejercicios propuestos

Solución Ejercicio 1:

String devolverElementoLista({
	int posicion = 0,
	required List<String> lista,
}) {
	if (lista.isEmpty) {
		return 'Sin datos';
	}

	if (
		posicion < 0 ||
		posicion >= lista.length
	) {
		return 'Índice fuera de rango';
	}

	return lista[posicion];
}

void main() {
	final lista = <String>[
		'Uno',
		'Dos',
		'Tres',
		'Cuatro',
	];

	print(
		devolverElementoLista(
			lista: lista,
		),
	);

	print(
		devolverElementoLista(
			posicion: 2,
			lista: lista,
		),
	);

	print(
		devolverElementoLista(
			lista: lista,
			posicion: 4,
		),
	);

	print(
		devolverElementoLista(
			posicion: -1,
			lista: lista,
		),
	);
}


Solución Ejercicio 2:

int getNumPlatosMasCaros({
	required Map<int, double> mapa,
	required double precio,
}) {
	return mapa.values
		.where(
			(precioMapa) => precioMapa > precio,
		)
		.length;
}

void main() {
	final precios = <int, double>{
		1: 10.34,
		2: 3.24,
		3: 24.99,
		4: 17.35,
	};

	precios.addAll({
		5: 9.23,
		6: 2.22,
	});

	print(precios);

	final ultimaClave = precios.keys.last;
	precios.remove(ultimaClave);

	precios.forEach((clave, valor) {
		if (valor < 5) {
			print(
				'La clave $clave tiene un precio de $valor',
			);
		}
	});

	const precioReferencia = 10.0;

	final numPlatos = getNumPlatosMasCaros(
		mapa: precios,
		precio: precioReferencia,
	);

	print(
		'Número de platos con un precio superior '
		'a $precioReferencia euros: $numPlatos',
	);
}


Solución Ejercicio 3:

void buscarCadena(
	Set<String> conjunto,
	String cadena,
) {
	final encontrados = conjunto.where(
		(elemento) => elemento.contains(cadena),
	);

	for (final elemento in encontrados) {
		print('Encontrado: $elemento');
	}
}

void main() {
	final equipo = <String>{
		'Base',
		'Alero',
		'Pivot',
		'Escolta',
	};

	var cadenaBusqueda = 'as';

	print(
		'Cadena de búsqueda: $cadenaBusqueda',
	);

	buscarCadena(
		equipo,
		cadenaBusqueda,
	);

	cadenaBusqueda = 's';

	print(
		'Cadena de búsqueda: $cadenaBusqueda',
	);

	buscarCadena(
		equipo,
		cadenaBusqueda,
	);
}


Solución Ejercicio 4:

String sonMayores({
	double numero = 0,
	required List<double> lista,
}) =>
	lista.every(
		(elemento) => elemento > numero,
	)
		? 'SI'
		: 'NO';

void main() {
	final listaNumeros = <double>[
		10.0,
		11.22,
		15.0,
		7.0,
		3.44,
	];

	var numeroReferencia = 2.0;

	print(
		'Todos los números de la lista son mayores '
		'a $numeroReferencia: '
		'${sonMayores(
			numero: numeroReferencia,
			lista: listaNumeros,
		)}',
	);

	numeroReferencia = 12.0;

	print(
		'Todos los números de la lista son mayores '
		'a $numeroReferencia: '
		'${sonMayores(
			lista: listaNumeros,
			numero: numeroReferencia,
		)}',
	);
}


Solución Ejercicio 5:

import 'dart:math';

void main() {
	final random = Random();

	// 100 números aleatorios entre 1 y 100.
	final numerosAleatorios = List<int>.generate(
		100,
		(_) => random.nextInt(100) + 1,
	);

	print(numerosAleatorios);

	// Números desde 1 hasta 100.
	// Lista de longitud fija.
	final numerosSecuenciales = List<int>.generate(
		100,
		(posicion) => posicion + 1,
		growable: false,
	);

	print(numerosSecuenciales);

	// Cuadrados desde 1 hasta numero.
	// La lista permite añadir elementos.
	const numero = 10;

	final numerosAlCuadrado = List<int>.generate(
		numero,
		(posicion) {
			final valor = posicion + 1;

			return valor * valor;
		},
		growable: true,
	);

	print(numerosAlCuadrado);

	numerosAlCuadrado.add(121);

	print(numerosAlCuadrado);
}




Enlace a la página principal de la UD2

Enlace a la página principal del curso


```