Diferencia entre revisiones de «Flutter DART variables - tipos de datos»
Ir a la navegación
Ir a la búsqueda
Imagen obtenido de este sitio
Imagen obtenida de esta web
(→Mapas) |
(→Enum) |
||
Línea 934: | Línea 934: | ||
+ | |||
+ | |||
+ | <br /> | ||
+ | ==Ejercicios propuestos== | ||
+ | |||
+ | * '''Ejercicio 1:''' En un mismo programa ejecuta las siguientes órdenes. | ||
+ | |||
+ | : Define una variable de nombre valorMedio que tenga de valor 12.2321 y haz que sólo se muestre 1 decimal. | ||
+ | : Asigna a la variable anterior el valor 'Juan' y añade dentro de una orden print, el valor Fernández. | ||
+ | |||
+ | |||
+ | |||
+ | <br /> | ||
+ | * '''Ejercicio 2:''' En un mismo programa ejecuta las siguientes órdenes. | ||
+ | : Define una variable entera de nombre var1 con valor inicial 0. | ||
+ | : Define una constanta de nombre numeros, con valor 10. | ||
+ | : Suma a la variable var1, los números indicados en al constante numeros. Por ejemplo, si numeros vale 5, debemos sumar a var1: 1+2+3+4+5. | ||
+ | : Asigna a la variable media el resultado de dividir la suma anterior entre numeros. Dicha variable debe guardar sólo 2 dígitos decimales. | ||
+ | : Muestra empleado la orden print (haz todo lo necesario dentro de dicha orden) la siguiente frase: La suma de los XX primeros números da YY y la media es de ZZ.CC. | ||
+ | |||
+ | |||
+ | |||
+ | <br /> | ||
+ | * '''Ejercicio 3:''' En un mismo programa ejecuta las siguientes órdenes. | ||
+ | : Define una función de nombre concatenar, que dados 3 datos (no sabes los tipos) devuelva una cadena con la concatenación de los 3 valores recibidos, separados por guiones. | ||
+ | : Define tres constantes con los siguientes valores: 'CASA', 'COMPRADA', Fecha_Actual (aparecerá también la hora y en formato inglés) | ||
+ | : Muestra empleando la orden print, el resultado de llamar a la función anterior. | ||
+ | : Define una variable de nombre cadena y valor inicial 'VENDIDA'. | ||
+ | : Guarda en una constante el resultado de llamar a la función enviando como datos 'CASA', VENDIDA', Fecha_Actual | ||
+ | : Muestra el valor de la constante anterior. | ||
+ | : Muestra empleando la orden print, el resultado de llamar a la función anterior con los siguientes datos: 'MANSION','PRECIO',12543.45. (cuidado con las comillas, también puedes emplear las doble comillas dentro de print :) ) | ||
+ | |||
+ | |||
+ | : <u>Nota:</u> Dart-Flutter tienen muchos 'paquetes' que permiten aumentar las funcionalidades. Si te atreves, busca en https://pub.dev/ el paquete intl y emplea la función DateFormat para dar el formato español a la fecha. Para instalarlo necesitas 'parar' la ejecución y volver a ejecutar el programa una vez modifiques el archivo pubspec.yaml. | ||
+ | |||
+ | |||
+ | |||
+ | |||
+ | <br /> | ||
+ | ===Soluciones ejercicios propuestos=== | ||
+ | |||
+ | * '''Ejercicio 1:''' En un mismo programa ejecuta las siguientes órdenes. | ||
+ | |||
+ | : Define una variable de nombre valor_medio que tenga de valor 12.2321 y haz que sólo se muestre 1 decimal (haz todo lo necesario dentro de la orden print). | ||
+ | : Asigna a la variable anterior el valor 'Juan' y añade dentro de una orden print, el valor Fernández. | ||
+ | :<syntaxhighlight lang="java" enclose="div" highlight="" > | ||
+ | void main() { | ||
+ | |||
+ | dynamic valorMedio = 12.2321; | ||
+ | |||
+ | print('${valorMedio.toStringAsFixed(1)}'); | ||
+ | |||
+ | valorMedio = 'Juan'; | ||
+ | print('$valorMedio Fernández'); | ||
+ | |||
+ | } | ||
+ | </syntaxhighlight> | ||
+ | |||
+ | |||
+ | |||
+ | <br /> | ||
+ | * '''Ejercicio 2:''' En un mismo programa ejecuta las siguientes órdenes. | ||
+ | : Define una variable entera de nombre var1 con valor inicial 0. | ||
+ | : Define una constanta de nombre numeros, con valor 10. | ||
+ | : Suma a la variable var1, los números indicados en al constante numeros. Por ejemplo, si numeros vale 5, debemos sumar a var1: 1+2+3+4+5. | ||
+ | : Asigna a la variable media el resultado de dividir la suma anterior entre numeros. Dicha variable debe guardar sólo 2 dígitos decimales. | ||
+ | : Muestra empleado la orden print (haz todo lo necesario dentro de dicha orden) la siguiente frase: La suma de los XX primeros números da YY y la media es de ZZ.CC. | ||
+ | |||
+ | :<syntaxhighlight lang="java" enclose="div" highlight="" > | ||
+ | void main() { | ||
+ | |||
+ | |||
+ | const numeros = 10; // Mejor const ya que se guarda en compilación | ||
+ | int var1=0; | ||
+ | for(int cont=1; cont < numeros; cont++){ | ||
+ | var1 += cont; | ||
+ | } | ||
+ | double media = double.parse((var1/numeros).toStringAsFixed(2)); | ||
+ | |||
+ | print('La suma de los $numeros primeros números es de $var1 y la media es de $media'); | ||
+ | |||
+ | |||
+ | } | ||
+ | </syntaxhighlight> | ||
+ | |||
+ | |||
+ | <br /> | ||
+ | |||
+ | |||
+ | |||
+ | * '''Ejercicio 3:''' En un mismo programa ejecuta las siguientes órdenes. | ||
+ | : Define una función de nombre concatenar, que dados 3 datos (no sabes los tipos) devuelva una cadena con la concatenación de los 3 valores recibidos, separados por guiones. | ||
+ | : Define tres constantes con los siguientes valores: 'CASA', 'COMPRADA', Fecha_Actual (aparecerá también la hora y en formato inglés) | ||
+ | : Muestra empleando la orden print, el resultado de llamar a la función anterior. | ||
+ | : Define una variable de nombre cadena y valor inicial 'VENDIDA'. | ||
+ | : Guarda en una constante el resultado de llamar a la función enviando como datos 'CASA', VENDIDA', Fecha_Actual | ||
+ | : Muestra el valor de la constante anterior. | ||
+ | : Muestra empleando la orden print, el resultado de llamar a la función anterior con los siguientes datos: 'MANSION','PRECIO',12543.45. (cuidado con las comillas, también puedes emplear las doble comillas dentro de print :) ) | ||
+ | |||
+ | :<syntaxhighlight lang="java" enclose="div" highlight="" > | ||
+ | String concatenar(Object par1, Object par2, Object par3){ // Mejor Object que dynamic ya que no vamos necesitar llamar a ningún método fuera de Object | ||
+ | |||
+ | return '$par1-$par2-$par3'; | ||
+ | |||
+ | } | ||
+ | |||
+ | void main() { | ||
+ | |||
+ | const c1 = 'CASA'; | ||
+ | const c2 = 'COMPRADA'; | ||
+ | final c3 = DateTime.now(); | ||
+ | |||
+ | print('Resultado llamar a concatenar: ${concatenar(c1,c2,c3)}'); | ||
+ | |||
+ | |||
+ | String cadena = 'VENDIDA'; | ||
+ | final resultado = concatenar(c1,cadena,c3); | ||
+ | print('Nueva llamada: $resultado'); // Debemos aconstumbrarnos a emplear las variables dentro de las comillas | ||
+ | |||
+ | print('Otra llamada: ${concatenar("MANSION","PRECIO",12543.45)}'); | ||
+ | |||
+ | |||
+ | } | ||
+ | </syntaxhighlight> | ||
<br /> | <br /> |
Revisión del 10:57 29 ago 2022
Sumario
Introducción
- Para aplicar los tipos de datos a variables necesitamos saber como definir variables en DART.
- Para definir una variable anteponemos el tipo de dato a su nombre de la forma: tipo_dato nombre_variable;
- Los nombre de las variables pueden tener las siguientes reglas de estilo: https://dart.dev/guides/language/effective-dart/style
- Los diferentes operadores que se pueden aplicar en DART: https://www.geeksforgeeks.org/operators-in-dart/#:~:text=The%20operators%20are%20special%20symbols,on%20one%20or%20two%20operands.
Tipos de datos numéricos
- Dart dispone de dos tipos de datos:
- enteros (int) : desde -infinito a +infinito sin decimales.
- decimales (double): desde -infinito a +infinito con decimales.
- En la siguinte imagen podemos ver como implementa cada tipo de dato DART en el código nativo donde se vaya a ejecutar la aplicación.
- Ejemplo de código:
void main() { int edad=15; double peso = 45.36; print("El alumno con edad $edad tiene un peso de $peso"); }
- Comentarios:
- Las variables están inicializadas en la definición.
- Fijarse en la línea del print, como podemos emplear dentro de cadenas, variables definidas en Dart. Es necesasrio emplear el símbolo $nombrevariable. De esta forma nos ahorramos el tener que concatenar y convertir variables con tipos de datos diferentes.
Comparando tipos de datos numéricos
- Indicar que Dart dispone de la función identical para determinal cuando dos números son iguales en valor y tipo.
- El resultado varía si la aplicación se ejecuta en la Web y en otra plataforma (la implementación del tipo de dato double en la web es también int):
- Veamos un ejemplo, cuyo resultado es diferente si lo ejecutais en la Web o en el Android Studio:
void main(){ int i_edad = 0; double d_edad = 0.0; if (i_edad==d_edad) print('$i_edad es igual a $d_edad'); if (!identical(i_edad,d_edad)) print('$i_edad no es idéntica a $d_edad'); }
- Nota: Podemos emplear la función toStringAsFixed para mostrar un número de decimales concreto:
- print('$i_edad es igual a ${d_edad.toStringAsFixed(1)}');
- Fijarse que si lo hacemos dentro del print, necesitamos emplear las llaves (lo veremos posteriormente).
Nota: Existe otro tipo de dato, num que es el tipo del cual derivan int y double. Por lo tanto permite almacenar tanto valores enteros como decimales.
- Antes de DART 2.1, si un número estaba definido como double, no podríamos asignar este valor: double var = 9; y tendríamos que poner: double var = 9.0;
- En ese caso sería necesario definir la variable como num. A partir de DARt 2.1 esto ya no es necesario y acepta ese tipo de asignación.
- Puede existir algún caso en el que sea necesario definir como num una variable, por ejemplo, si queremos llamar a una función con tipos de datos int/double (aunque sería más conveniente realizar un CAST).
void funcion(num val){ print (val); } void main() { double num1 = 10.32; int num2 = 1; funcion(num1); funcion(num2); }
Tipos de datos cadenas
- Para definir una cadena, anteponemos al nombre de la variable el tipo de dato String.
- Por ejemplo:
void main() { String nombre = 'Angel'; String apellidos = 'Fernández González'; String nombreCompleto = nombre + " " + apellidos; print("El nombre $nombre se junta con los apellidos $apellidos y forma $nombreCompleto"); }
Tipos de datos booleanos
- Al igual que en otros lenguajes de programación, para definir una variable booleana (que puede guardar valores true/false/null) la definimos de la siguiente forma:
void main() { bool encendido = true; if (encendido) { print('Está encendido.'); } else{ print('No está encendido'); } }
- Nota:: Al escribir este código podéis comprobar como https://dartpad.de avisa en la parte else de que ese código no se va a ejecutar nunca (aparece subrayado y al situar el cursor en esa parte del código indica Dead Code.
- Si quisiéramos probar a escribir por teclado un valor para determinar si es cierto o falso, tendríamos que ejecutar el siguiente código en el Android Studio u otro IDE de escritorio:
import 'dart:io'; void main() { bool encendido = int.parse(stdin.readLineSync().toString()) == 1 ? true : false; if (encendido) { print('Está encendido.'); } else{ print('No está encendido'); } }
Tipos de datos dinámicos
- Son variables de las cuales no sabemos que tipo de dato va a ser hasta que se asignen a un valor y cojerán el tipo de dato del valor asignado.
- Podemos definirlas de tres formas:
- Con la palabra reservada var.
- Con la palabra reservada dynamic.
- Con la palabra reservada Object.
Definidos con var
- Podemos definir una variable con la sintaxis: var nombre_variable;
- Si no inicializamos un valor, el tipo de dato asociado a estar variable será dynamic
- Por ejemplo:
void main() { var nombre; nombre = "Angel" print(nombre); }
- En este caso, nombre no tiene asociado un tipo de dato. Al asignarle el valor "Angel" pasa a ser de tipo String, pero al no tener una asignación en la definición, podríamos asignarle un valor numérico y pasaría a ser un tipo de datos numérico.
- Por ejemplo:
var variable; variable = "Angel"; // Ahora es una cadena variable = 12; // Ahora es un número variable = variable + 1; print(variable);
- En el caso de dar un valor inicial, pasa a ser del tipo del valor asignado y ya no se podría cambiar por otro tipo, por lo que:
var variable='Angel'; // Variable de tipo String => EQUIVALENTE A => String variable='Angel'; variable = 10; // ===> DARIA UN ERROR
- Se recomienda la definición de variables de esta forma (con var y asignación de valor por defecto).
Definidos con dynamic
- Tenemos que anteponer la palabra reservada dynamic antes del nombre de la variable.
- Por ejemplo:
void main() { dynamic nosetipo='valor'; if (nosetipo is dynamic) print ('Es dinámica'); if (nosetipo is String) print ('Es una cadena'); nosetipo = 1; if (nosetipo is int) print ('Es un número'); }
- Por lo tanto si definimos una variable 'var' sin asignar valor o una variable 'dynamic', no habría diferencias entre ellas en cuanto a la asignación de valores de diferentes tipos.
- La diferencia con var se encuentra en que podemos llamar a métodos en los que no sabemos si se encuentran definidos o no dentro de la clase en tiempo de compilación.
class Manzana { double peso = 10.3; void getSabor(){ print ('El sabor es ácido'); } } void main() { Manzana manzana = new Manzana(); dynamic nose_dynamic = manzana; nose_dynamic.getColor(); // NO DARÍA ERROR EN COMPILACIÓN A PESAR QUE NO EXISTA EL MÉTODO var nose_var = manzana; nose_var.getColor(); // DARÍA ERROR EN COMPILACIÓN }
- Con dynamic le estamos diciendo a DART que no chequee si los métodos que vamos a llamar se encuentran definidos o no en la clase.
- Otra diferencia la encontramos cuando definimos métodos que devuelvan un tipo de dato desconocido (que pueda variar).
- En ese caso debemos definirlos como 'dynamic', ya que si lo intentemos hacer con 'var' daría un error:
dynamic getDato(int tipo){ if (tipo==1) return 'Devuelvo cadena'; else return 100; // Devuelvo número } void main() { dynamic valor = getDato(1); print('Valor es cadena: $valor'); valor = getDato(0); print('Valor es número: $valor'); }
Definidos con Object
- A diferencia de dynamic, con Object estamos indicando que lo que vamos a recibir será un objeto de una clase.
- Por tanto podremos llamar a los métodos definidos en la clase Object (por ejemplo toString).
- El caso anterior también funcionaría con Object:
Object getDato(int tipo){ if (tipo==1) return 'Devuelvo cadena'; else return 100; // Devuelvo número } void main() { Object valor = getDato(1); print('Valor es cadena: $valor'); valor = getDato(0); print('Valor es número: $valor'); }
Constantes
- En DART tenemos dos modificadores para definir una constante:
- const: Se inicializa en compilación.
- final: Se inicializa en ejecución.
- Por ejemplo:
void main() { const int numeroAlas = 10; // Se inicializa en compilación (antes de ejecución) final DateTime fechaActual = DateTime.now(); // Se inicializa en ejecución print (numeroAlas); print (fechaActual); }
Nota: Indicar que podríamos ahorrarnos el poner el tipo de dato en la definición ya que asignaría el tipo de dato en base al valor por defecto.
- En este ejemplo, no podríamos declarar la constante fechaActual como const ya que en compilación no podemos asignar la fecha actual.
- Otra situación en la que se ve la diferencia entre los dos modificadores es cuando lo aplicamos a objetos de una clase.
- Por ejemplo, si lo aplicamos a un Array (una lista), si definimos el array como const no podríamos añadir nuevos elementos a la lista (el objeto es inmutable).
- Sin embargo, si lo definimos como final podríamos añadir o borrar valores a la lista.
void main() { final datos = <int>[1,2,3]; print(datos); datos.add(4); print(datos); datos.remove(1); print(datos); }
- Sin embergo poniendo const, en Android Studio dará un unhandle exception (en la Web no continuará con la ejecución).
Conversión de tipos de datos
- Cada tipo de dato tiene funciones que permite su conversión a otro tipo.
- Lo más fácil es buscar cual es cuando se necesite.
- Al poner un punto después de la variable, aparecen un conjunto de funciones que se pueden aplicar a dicho tipo.
- Por ejemplo, para convertir un double a un int:
void main() { int val1 = 10; int val2 = 15; int resul = (val2/val1).toInt(); print(resul); }
- También se puede hacer uso de los métodos parse de cada tipo de dato, como int.parse para convertir una cadena a un entero o double.parse para convertir una cadena a un double.
- Para convertir a cadena podemos emplear los métodos toString() y toStringAsFixed si queremos guardar un número de dígitos decimales concreto.
Valores nulos
- Cuando definimos una variable puede ser que no tengamos un valor que darle, y que,por tanto, sea desconocido.
- Ese tipo de valor es lo que se conoce como valor null.
- Normalmente se emplea en variables que pertenecen a una clase y que todavía no hemos instanciado.
- DART incorpora un mecanimos de seguridad de empleo de valores nulos denomiado NULL SAFETY.
- Este mecanimo impide que se pueda asignar un valor null a variables que no debeiran de poder guardar dicho valor.
- Tener en cuenta que si a una variable le llega un valor null y no tenemos programado el uso con ese valor, normalmente el programa romperá y dejará de ejecutarse, pudiendo llegar a ser un problema de seguridad.
- Veamos un ejemplo:
void main() { String cadena = 'Angel'; cadena = null; print(cadena); }
- Este mecanimos puede ser muy útil cuando sepamos que no debería tener valores nulos una determinada variable, por ejemplo;
int getLength(String cadena){ return cadena.length; } void main() { String cadena = 'Angel'; print(getLength(null)); }
- Como vemos, el método getLength() creado por mí, espera recibir una cadena, pero dicha cadena nunca va a poder ser null...
- Si estamos trabajando en Web podemos inhabilitar el mecanimo de seguridad en la parte baja:
aunque no es recomendable hacerlo
- Para solucionar el problema en caso de necesidad (es decir, que tenemos que definir una variable que sabemos que va a poder tener valores nulos) debemos de utilizar el símbolo intorrogación al lado del tipo de dato de la forma siguiente:
void main() { String? cadena = 'Angel'; cadena = null; print(cadena); }
- Veamos otro ejemplo en la llamada a un método en el que indicamos que el parámetro va a poder recibir valores nulos:
void imprimirEstado(bool? valor){ if (valor==true) { print('El valor es true'); } else if (valor == null) { print('El valor es null'); } else { print('El valor es false'); } } void main() { bool? encendido = true; imprimirEstado(encendido); encendido = null; imprimirEstado(encendido); }
- Existen una serie de operadores que podemos emplear relacionados con el valor nulo:
- Operador de aserción ! : Si sabemos seguro que una variable, a pesar de que acepta valores nulos, no va a tener un valor nulo, podemos asignarla a otra variable:
int? varPuedeTenerNulo=1; int varSinNulo = 1; void main(){ varSinNulo = varPuedeTenerNulo!; // Si no ponemos la admiración daría un error ya que no podemos asignar una variable que puede aceptar valores nulos a otra que no. }
- Operador consciente de nulos ? : Va pegado a una variable a la que queremos llamar a un metodo (al ser una variable que deriva de una Clase, y por tanto tenemos acceso a sus métodos) y sólo queremos que lo haga cuando la variable no sea nula.
String? varPuedeTenerNulo; void main(){ int? numCar = varPuedeTenerNulo?.length; // length daría una excepción si la variable fuese nula print (numCar); }
- Operador ?? : Utilizado para asignar un valor a una varible, comprobando que el valor no sea nulo. Si es nulo, le asigna un valor especificado.
String? varPuedeTenerNulo; void main(){ String cadena = varPuedeTenerNulo ?? 'Por defecto'; // Si vale null, devuelve la cadena 'Por defecto' y sino la cadena print (cadena); varPuedeTenerNulo = 'Nueva Cadena'; cadena = varPuedeTenerNulo ?? 'Por defecto'; print (cadena); }
- Más información: https://dart.dev/null-safety/understanding-null-safety
Listas
- Conjunto de datos que tienen todos el mismo tipo (fijarse que si la definimos como de tipo dynamic, podrían albergar 'tipos' diferentes).
- Lo definimos con la palabra List.
- Podéis:
- Consultar en este enlace todos las propiedades y métodos de la clase List.
- Métodos útiles en el manejo de listas.
- Podríamos decir que sería equivalentes a las listas de Java.
Un ejemplo:
void main() { List nombres = ['Angel','Pedro','Ana']; print(nombres); nombres.add('Luisa'); print(nombres); nombres.removeAt(1); nombres.remove('Ana'); print(nombres); }
- Nota Importante: Fijarse que al no indicar el tipo de dato de cada uno de los elementos de la lista, DART la define como de tipo <dynamic>
- Por lo tanto, al código anterior podríamos añadir cualquier dato de cualquier tipo, ya que todos son dynamic.
- Es mejor indicar el tipo de dato que va a guardar la lista:
void main() { List<String> nombres = ['Angel','Pedro','Ana']; // var nombres = <String>['Angel','Pedro','Ana']; // Otra forma de definir una lista de Strings print(nombres); }
Recorriendo listas
- Veremos posteriormente con las funciones otras formas más rápidas de recorrer listas.
- Por ahora, veamos la forma 'tradicional' empleando un contador desde la posición 0 hasta el número de elementos de la lista.
void main() { List<String> nombres = ['Angel','Pedro','Ana']; print(nombres); nombres.add('Luisa'); for(var i=0; i<nombres.length;i++){ print('Posición $i => valor ${nombres[i]}'); } }
- Fijarse como para poder emplear nombres[i] dentro de la cadena, debemos de emplear { }. Si no lo hiciéramos, sólo podríamos acceder a 'nombres', es decir, a todo la lista completa.
- También podemos recorrerla * empleado iterator:
void main() { List<String> nombres = ['Angel','Pedro','Ana']; var iter = nombres.iterator; while(iter.moveNext()){ print('El elemento de la lista: ${iter.current}'); } }
- Aunque lo más normal es emplear la forma for...in:
void main() { List<String> nombres = ['Angel','Pedro','Ana']; for(String valor in nombres){ print('El elemento de la lista $valor'); } }
- Nota: Veremos más adelante que existe otra forma, empleando el método forEach() que lleva como argumento una función a la cual va a llamar por cada elemento de la lista.
Mapas
- A diferencia de las listas, este tipo de almacenamiento permite guardar un valor 'clave' y asociar dicha entrada a un valor 'asociado'.
- Sería el equivalente a los mapas de Java.
- Consultar en este enlace todos las propiedades y métodos de la clase Map.
- Al igual que todo lo demás, podríamos definirlo como var, final o const, pero digamos que la palabra reservada para definirla es: Map
- Veamos un ejemplo:
void main() { Map<String,dynamic> ordenador = { 'marca' : 'HP', 'hd' : 2000, 'cpu' : '4ghz', 'nucleos' : 8, 'ssd' : true }; print(ordenador); }
Nota: Fijarse que en la definición del Mapa establecemos el tipo de dato:
- De la clave
- Del dato asociado a la clave.
- En el ejemplo, la clave siempre tiene un valor 'cadena' mientras que los datos asociados a esas claves varían (String, boolean, numérico) por eso lo definimos como dynamic. Podríamos tener también la clave como dynamic si tivéramos como clave valores de cualquier tipo, como boolean, numérico,....
- Si queremos acceder al valor de una clave cualquiera, lo haremos de una forma parecida a las listas (pero no confindirse, en las listas ponemos la posición mientras que en los mapas ponemos el valor de la clave
void main() { Map<String,dynamic> ordenador = { 'marca' : 'HP', 'hd' : 2000, 'cpu' : '4ghz', 'nucleos' : 8, 'ssd' : true }; print("El ordenador ${ordenador['marca']} con un disco de ${ordenador['hd']} GB funciona a una velocidad de ${ordenador['cpu']} teniendo ${ordenador['nucleos']} núclos. "); ordenador['ssd'] == true ? print ('SSD:SI') : print ('SSD:NO'); }
- Fijarse que para acceder a un elemento concreto dentro de una cadena tenemos que encerrar la expresión entre { } como ya hicimos antes con las listas.
- Veamos un ejemplo en el que añadimos y quitamos elementos al mapa:
void main() { Map<String,dynamic> ordenador = { 'marca' : 'HP', 'hd' : 2000, 'cpu' : '4ghz', 'nucleos' : 8, 'ssd' : true }; ordenador.remove('hd'); // Elimima una entrada print(ordenador); ordenador.addAll({'precio' : 1000.34, 'oferta' : '10%'}); // Añadimos dos entradas print(ordenador); }
- Nota: Otra forma de añadir nuevos elementos es simplemente asignar a la nueva clave un nuevo valor de la forma: ordenador['stock'] = 10;
- En DART existen otros tipos de mapas al visto en estos ejemplos.
- Podéis consultar los diferentes tipos en: https://api.dart.dev/stable/2.13.4/dart-core/Map-class.html
Recorriendo mapas
- Veremos con las funciones otras formas de recorrer un mapa.
- Por lo de ahora vamos a ver dos formas:
- En una no necesitamos acceder a las claves, sólamente a los valores.
- En otra accedemos a las claves y los valores del mapa.
- Accediendo sólo a los valores:
void main() { Map<String,dynamic> ordenador = { 'marca' : 'HP', 'hd' : 2000, 'cpu' : '4ghz', 'nucleos' : 8, 'ssd' : true }; for(dynamic valor in ordenador.values){ print("Valor obtenido:$valor"); } }
- Fijarse que debemos de poner en valor el tipo de dato con el que esté definido el map para los valores.
- Accediendo a las claves y los valores:
void main() { Map<String,dynamic> ordenador = { 'marca' : 'HP', 'hd' : 2000, 'cpu' : '4ghz', 'nucleos' : 8, 'ssd' : true }; for(MapEntry<String,dynamic>mpentry in ordenador.entries){ print("Clave obtenida: ${mpentry.key} Valor obtenido:${mpentry.value}"); } }
- En este caso creamos una variable de tipo MapEntry que representa cada una de las entradas del mapa. Cada entrada del mapa lo forma un par de clave-valor de tipo <String,dynamic> que es como está definido en el mapa y por eso mpentry tiene que ser de ese tipo.
- Posteriormente dentro del bucle podemos acceder a las propiedades:
- key: Para acceder a la clave.
- value: Para acceder al valor asociado a esa clave.
Valores nulos al utilizar mapas
- Cuando definimos un mapa y queremos recuperar el valor de una clave, si no usamos como tipo de dato de los valores 'dynamic' tendremos un problema.
- Veamos cual.
- Imaginemos que en el ejemplo anterior definimos el mapa de tipo <String, String>
void main() { Map<String,String> ordenador = { 'marca' : 'HP', 'hd' : '2000', 'cpu' : '4ghz', 'nucleos' : '8', 'ssd' : '1' }; }
- Si ahora intentamos asignar el valor a una variable nos dará el siguiente error:
- Lo que está indicando es que no se puede asignar algo que puede devolver null a una variable que no acepta valores nulos.
void main() { Map<String,String> ordenador = { 'marca' : 'HP', 'hd' : '2000', 'cpu' : '4ghz', 'nucleos' : '8', 'ssd' : '1' }; String valor = ordenador['marca']; }
Para resolver este problema tenemos 3 posibles soluciones:
- Definir la variable como que acepta valores nulos:
String? valor = ordenador['marca']; print(valor);
- Indicar a DART que tiene que devolver en caso de que el valor para esa clave del mapa sea nulo. Para eso empleamos el operador ??:
String valor = ordenador['nada'] ?? 'Opel'; print(valor);
- Indicarle a DART que puede confiar en nosotros y que sabemos que el valor a asignar nunca va a ser null. Para ello empleamos el operador ! de la forma:
String valor = ordenador['marca']!; // LLeva ! al final print(valor);
Conjuntos (set)
- Los conjuntos son un tipo de dato que guarda valores siempre del mismo tipo y no permite duplicados.
- Las diferencias con las listas son:
- Los conjuntos guardan los valores de forma desordenada (en las listas aparecen en el orden en que son añadidos).
- No permite guardar valores duplicados.
- No se permite acceder al elemento del conjunto empleando un índice como sucede en las listas.
- La forma de definir un conjunto es:
var setName = <type>{}; // CUIDADO, ya que si no indicamos el tipo de datos, será definido como un mapa de literales. var setName = {'valor1','valor2',....}; // Aquí no definimos el tipo, pero al dar unos valores iniciales Dart ya sabe que es un conjunto de String´s Set<type> setName = {};
- Veamos algunas operaciones básicas:
void main() { var conjunto = {'Angel','Luis','Ana','María'}; print(conjunto); conjunto.add('Pedro'); // Añade un elemento conjunto.remove('Angel'); // Borra un elemento print(conjunto); print(conjunto.elementAt(0)); // Elemento de la posición 0 conjunto.clear(); // Borra todos los elementos }
- En DART existen otros tipos de conjuntos del visto en estos ejemplos.
- Podéis consultar los diferentes tipos en: https://api.dart.dev/stable/2.13.4/dart-core/Set-class.html
Recorriendo conjuntos
- De una forma parecida a las listas:
void main() { var conjunto = {'Angel','Luis','Ana','María'}; print(conjunto); conjunto.add('Pedro'); // Añade un elemento conjunto.remove('Angel'); // Borra un elemento for(int i=0; i<conjunto.length;i++){ print('Elemento del conjuinto: ${conjunto.elementAt(i)}'); } }
void main() { var conjunto = {'Angel','Luis','Ana','María'}; var iter = conjunto.iterator; while(iter.moveNext()){ print('El elemento del conjunto: ${iter.current}'); } }
- Veremos con las funciones otras formas de recorrer los conjuntos.
Enum
- Son un tipo especial de clase utilizada para representar un número fijo de valores constantes.
- La definición es: enum Valores { valor1, valor2, valor...};
- A cada valor del tipo enum se le asigna número empezando por el 0, pudiendo acceder a dichos valores de la forma Valores.values[posición]
- Veamos un ejemplo:
enum Estado { parado, corriendo, pausado, } void main(){ Estado estado = Estado.parado; print('El estado actual es $estado'); print('El valor de la posición 1 del tipo enum Estado es ${Estado.values[1]}'); Estado.values.forEach((estado) => print('Estado $estado')); }
Ejercicios propuestos
- Ejercicio 1: En un mismo programa ejecuta las siguientes órdenes.
- Define una variable de nombre valorMedio que tenga de valor 12.2321 y haz que sólo se muestre 1 decimal.
- Asigna a la variable anterior el valor 'Juan' y añade dentro de una orden print, el valor Fernández.
- Ejercicio 2: En un mismo programa ejecuta las siguientes órdenes.
- Define una variable entera de nombre var1 con valor inicial 0.
- Define una constanta de nombre numeros, con valor 10.
- Suma a la variable var1, los números indicados en al constante numeros. Por ejemplo, si numeros vale 5, debemos sumar a var1: 1+2+3+4+5.
- Asigna a la variable media el resultado de dividir la suma anterior entre numeros. Dicha variable debe guardar sólo 2 dígitos decimales.
- Muestra empleado la orden print (haz todo lo necesario dentro de dicha orden) la siguiente frase: La suma de los XX primeros números da YY y la media es de ZZ.CC.
- Ejercicio 3: En un mismo programa ejecuta las siguientes órdenes.
- Define una función de nombre concatenar, que dados 3 datos (no sabes los tipos) devuelva una cadena con la concatenación de los 3 valores recibidos, separados por guiones.
- Define tres constantes con los siguientes valores: 'CASA', 'COMPRADA', Fecha_Actual (aparecerá también la hora y en formato inglés)
- Muestra empleando la orden print, el resultado de llamar a la función anterior.
- Define una variable de nombre cadena y valor inicial 'VENDIDA'.
- Guarda en una constante el resultado de llamar a la función enviando como datos 'CASA', VENDIDA', Fecha_Actual
- Muestra el valor de la constante anterior.
- Muestra empleando la orden print, el resultado de llamar a la función anterior con los siguientes datos: 'MANSION','PRECIO',12543.45. (cuidado con las comillas, también puedes emplear las doble comillas dentro de print :) )
- Nota: Dart-Flutter tienen muchos 'paquetes' que permiten aumentar las funcionalidades. Si te atreves, busca en https://pub.dev/ el paquete intl y emplea la función DateFormat para dar el formato español a la fecha. Para instalarlo necesitas 'parar' la ejecución y volver a ejecutar el programa una vez modifiques el archivo pubspec.yaml.
Soluciones ejercicios propuestos
- Ejercicio 1: En un mismo programa ejecuta las siguientes órdenes.
- Define una variable de nombre valor_medio que tenga de valor 12.2321 y haz que sólo se muestre 1 decimal (haz todo lo necesario dentro de la orden print).
- Asigna a la variable anterior el valor 'Juan' y añade dentro de una orden print, el valor Fernández.
void main() { dynamic valorMedio = 12.2321; print('${valorMedio.toStringAsFixed(1)}'); valorMedio = 'Juan'; print('$valorMedio Fernández'); }
- Ejercicio 2: En un mismo programa ejecuta las siguientes órdenes.
- Define una variable entera de nombre var1 con valor inicial 0.
- Define una constanta de nombre numeros, con valor 10.
- Suma a la variable var1, los números indicados en al constante numeros. Por ejemplo, si numeros vale 5, debemos sumar a var1: 1+2+3+4+5.
- Asigna a la variable media el resultado de dividir la suma anterior entre numeros. Dicha variable debe guardar sólo 2 dígitos decimales.
- Muestra empleado la orden print (haz todo lo necesario dentro de dicha orden) la siguiente frase: La suma de los XX primeros números da YY y la media es de ZZ.CC.
void main() { const numeros = 10; // Mejor const ya que se guarda en compilación int var1=0; for(int cont=1; cont < numeros; cont++){ var1 += cont; } double media = double.parse((var1/numeros).toStringAsFixed(2)); print('La suma de los $numeros primeros números es de $var1 y la media es de $media'); }
- Ejercicio 3: En un mismo programa ejecuta las siguientes órdenes.
- Define una función de nombre concatenar, que dados 3 datos (no sabes los tipos) devuelva una cadena con la concatenación de los 3 valores recibidos, separados por guiones.
- Define tres constantes con los siguientes valores: 'CASA', 'COMPRADA', Fecha_Actual (aparecerá también la hora y en formato inglés)
- Muestra empleando la orden print, el resultado de llamar a la función anterior.
- Define una variable de nombre cadena y valor inicial 'VENDIDA'.
- Guarda en una constante el resultado de llamar a la función enviando como datos 'CASA', VENDIDA', Fecha_Actual
- Muestra el valor de la constante anterior.
- Muestra empleando la orden print, el resultado de llamar a la función anterior con los siguientes datos: 'MANSION','PRECIO',12543.45. (cuidado con las comillas, también puedes emplear las doble comillas dentro de print :) )
String concatenar(Object par1, Object par2, Object par3){ // Mejor Object que dynamic ya que no vamos necesitar llamar a ningún método fuera de Object return '$par1-$par2-$par3'; } void main() { const c1 = 'CASA'; const c2 = 'COMPRADA'; final c3 = DateTime.now(); print('Resultado llamar a concatenar: ${concatenar(c1,c2,c3)}'); String cadena = 'VENDIDA'; final resultado = concatenar(c1,cadena,c3); print('Nueva llamada: $resultado'); // Debemos aconstumbrarnos a emplear las variables dentro de las comillas print('Otra llamada: ${concatenar("MANSION","PRECIO",12543.45)}'); }
Enlace a la página principal de la UD2
Enlace a la página principal del curso
-- Ángel D. Fernández González -- (2021).