Funciones
Es un bloque de código que se puede reutilizar y lo podemos llamar la veces que queramos. No repetir código.
Las funciones no sirven para abstraer información que no necesita el usuario.
Note
Las funciones son miembros de "Primer orden"; es decir, no necesitan estar dentro de una clase y se pueden asignar a variables.
Note
Se usa el nombre de "función", cuando NO pertenece a un clase. Como se debe nombrar a un función, asi como las variables tiene una forma para que sea mas facil nombrarla; las funciones también tienen una manera para distinguir si es una variable o una función.
Buenas prácticas
Solo debe hacer una sola cosa, y lo que haga lo debe hacer muy bien
Note
Note
El nombre de una función es un verbo (acción)
Argumento vs Parámetro
Vamos a usar la palabra argumento y parámetro como sinónimos.
Tipos de la función
Palabra reservada | Tipo que devuelve |
---|---|
void |
No devuelve nada |
String |
Devuelve un tipo String |
int |
Devuelve un tipo int |
double |
Devuelve un tipo double |
bool |
Devuelve un tipo Booleano |
Object |
Devuelve ese tipo de "Objeto", prácticamente todo en Dart |
Como se invoca una función
De la siguiente manera mandamos a invocar a una funcion, para que realice sus acciones pertinentes.
nombreDeFuncion(argumento1, argumento2,...); // Si no retornar nada
tipo variable = nombreDeFuncion(argumento1, argumento2,...); // en caso que retorne algo guardamos la referencia
Función básica (sin argumento ni retornos)
Vamos a definir un función llamada saludo
, de tipo void
, es decir, que no retorna nada, solo realiza acciones, dentro de ella mandaremos a imprimir unos mensajes. Entre los paréntesis no colocamos nada, porque no necesitamos argumentos para que la función realice sus acciones.
Declaramos otra función, donde usamos el objeto Random
, esto es para ver que también podemos hacer uso de cualquier librería que necesitemos en nuestras funciones. Obviamente, debemos hacer las importaciones necesarias.
En la función main
es donde mandamos a llamar a la función que creamos.
import 'dart:math';
void saludo() {
print("----------");
print("Hola");
print("----------");
}
void sumaRandom() {
int numero1 = Random().nextInt(100);
int numero2 = Random().nextInt(200);
print(numero1 + numero2);
}
void main(List<String> args) {
saludo();
saludo();
saludo();
sumaRandom()
sumaRandom()
}
Función básica (con argumentos)
Vamos a definir 3 funciones recibiendo diferente cantidad de argumentos, pero ninguna retorna algun resultado, dado que son tipo void
.
/**
Función que recibe un argumento, pero no devuelve nada
**/
void mensajePersonalizado(String nombre) {
print("Hola $nombre, Estamos en Dart!!!");
}
/**
Función que recibe dos argumentos, pero no devuelve nada
**/
void mensajeEspecialidad(String nombre, String especialidad) {
print("Hola $nombre, que padre que llevas la especialidad $especialidad");
}
/**
Función que recibe dos argumentos, pero no devuelve nada
**/
void mensaje10(String nombre, int edad) {
int edadNueva = edad + 10;
print("Hola $nombre,la edad que tendrás en 10 años es $edadNueva");
}
void main(List<String> args) {
mensajePersonalizado("Alfredo"); // invocamos y pasamos el argumento necesario
mensajeEspecialidad("Ethan", "Sistemas"); // invocamos y pasamos los argumentos necesarios
mensaje10("Adrian", 22); // invocamos y pasamos los argumentos necesarios
}
Función con retorno de datos (return
)
Vamos a conocer otra palabra reservada, llamada return
, esta palabra solo se usa dentro de funciones, y es lo ultimo que ejecuta la función, devolviendo lo que hallamos puesto que devolverá la función.
Cuando vamos a definir que retorna alguna referencia, se debe colocar precediendo al nombre de la función.
import 'dart:math';
/*
Esta función recibe 2 argumentos de tipo double, vamos a sumar estos parámetros y devolvemos este resultado, que es un double
*/
double suma(double numero1, double numero2) {
double resultado = numero1 + numero2;
return resultado;
}
void main(List<String> args) {
double sumatoria = suma(Random().nextDouble() * 100, 4);
print("La suma es $sumatoria");
}
Pasando y devolviendo parámetros nulos
En ocasiones podemos necesitar algunos parámetros en la funcion, esto dependiendo de lo que se necesite realizar dentro de la funcion, por lo tanto podemos manejar parámetros nulos. Se tiene que hacer la validación para usar el parámetro o no.
void mensajePersonalizado(String nombre, int? edad){
if(edad != null){
print("Hola $nombre, es un gusto que tengas $edad anos de edad");
}else{
print("Mucho gusto $nombre");
}
}
void main(){
mensajePersonalizado("Alejandro");
mensajePersonalizado("Carlos", 22);
}
En ocasiones también queremos devolver un valor nulo, por lo tanto, asi se define el tipo que se devuelve y que puede ser nulo.
String? mensaje(String? nombre){
if(nombre == null){
return null;
}else{
return "Hola $nombre!!!";
}
}
void main(){
String? valor1 = mensaje(null);
String? valor2 = mensaje("Manuel");
print(valor1);
print(valor2);
}
Parámetros opcionales ([ ]
)
En ocasiones por alguna razón, queremos parámetros opcionales que dependiendo si los pasaron haremos una cosa diferente a lo habitual, esto se puede lograr colocando corchetes cuadrados []
y ahi colocar todos los argumentos que queramos, estos deben ser definidos como tipo nulo, porque al ser opcionales pues por lógica deben ser así. Porque de lo contrario forzosamente deberíamos pasarlos.
Posición de parámetros opcionales
Siempre deben ir al final de los parámetros que recibe la funcion.
import 'dart:math';
/**
* Si solo me pasan la base, devuelve el cuadrado del numero,
* si me pasan la potencia, la base se elevara a esa potencia
*/
int potencia(int base, [int? potencia]){
if(potencia == null){
return pow(base,2).toInt();
}
return pow(base, potencia).toInt();
}
void main(){
int valor1 = potencia(2);
int valor2 = potencia(3,2);
print(valor1);
print(valor2);
}
Valores por default
También estos valores opcionales pueden tener valores por default, en caso que necesitemos hacer modificaciones, lo podemos hacer al pasar los parámetros a la funcion. En esta occasion al tener un valor, pues ya no es necesario maneja nulo en la declaración del parámetro.
import 'dart:math';
/**
* Si no me pasan la potencia, por default devuelve el cuadrado de la base
*/
int potencia(int base, [int potencia = 2]){
return pow(base, potencia).toInt();
}
void main(){
int valor1 = potencia(2);
int valor2 = potencia(3,2);
print(valor1);
print(valor2);
}
Parámetros nombrados ({ }
)
Dart permite tener parámetros nombrados en las funciones, haciendo mucho mas claro el parámetro con su valor. La sintaxis para indicar esto, es con llaves {}
; sin embargo, habitualmente hay que darle valores por default, o sino se deben aceptar nulos.
double calcularDistancia({double velocidad = 1, double tiempo = 1}) {
double distancia = velocidad / tiempo;
return distancia;
}
void main() {
double distancia = calcularDistancia(velocidad: 10, tiempo: 3);
print("La distancia es $distancia metros");
}
Se pueden combinar los parámetros habituales con los nombrados:
/**
* Se pasa un parámetro sin nombrar y otro nombrado con un valor por default
*/
double calcularFuerza(double masa, {double aceleracion = 9.8}) {
return masa * aceleracion;
}
void main() {
double fuerza = calcularFuerza(10, aceleracion: 1.62); //gravedad (aceleración) de la luna
print("La fuerza de una masa de 10kg en la luna es de $fuerza");
}
Parámetros requeridos (required
)
En ocasiones queremos usar parámetros nombrados pero, que no contengan un valor por default, sino que el usuario los pase al momento de usar la funcion; para esto existe una palabra reservada required
ante puesta al tipo del argumento:
/**
* El primer parámetro es nombrado y se debe pasar, el segundo es nombrado y opcional, pero contiene un valor por default
*/
double calcularFuerza({required masa, double aceleracion = 9.8}) {
return masa * aceleracion;
}
void main() {
double fuerza = calcularFuerza(masa: 10, aceleracion: 1.62); //gravedad (aceleración) de la luna
print("La fuerza de una masa de 10kg en la luna es de $fuerza");
}
Función anónima
Las funciones al ser miembros de primera clase, se pueden asignar a variables; es decir, tenemos el objeto tipo Function
, el cual podemos utilizar para declarar el tipo de la variable.
Como el nombre lo indica, se llama anónima porque la funcion no tiene nombre, solo se especifican todos sus partes pero, sin nombre de funcion.
void main() {
/**
* FORMA LARGA Y COMPLETA, ESPECIFICANDO CADA ELEMENTO
* Declaro una variable tipo Función, que devuelve un entero y recibe dos parámetros enteros
*/
int Function(int, int) multiplicar = (int valor1, int valor2) {
return valor1 * valor2;
};
/**
* FORMA CORTA
* Declaro una variable tipo Función, asignando una función anónima que recibe dos parámetros doubles yu devuelve un double
*/
Function division = (double valor1, double valor2) {
return valor1 / valor2;
};
print(valor);
print(valor2);
}
La forma mas habitual es pasar funciones como parámetros, mejor conocidas estas funciones como callbacks
.
void main() {
/**
* FORMA ANÓNIMA
* Paso directamente la función anónima para que realice la operación, dado que el parámetro que se recibe es una función
*/
var numeros = [1, 2, 3, 4];
numeros.forEach((element) { //estamos en el cuerpo de la función anónima
print("${element * 2}"); // se multiplica cada elemento de la lista por 2
});
int valor = multiplicar(4, 3);
double valor2 = division(3.2, 4.0);
}
/**
* Esta función recibe 2 enteros y un callback, el cual realiza la operación que se desee realizar
*/
void calcular(int a, int b, int Function(int, int) cb) {
int resultado = cb(a, b);
print(resultado);
}
void main(List<String> args) {
calcular(5, 4, (a, b) => a + b);
calcular(16, 9, (a, b) => a - b);
}
Función flecha (arrow
)
Las funciones flecha son una contracción de una funcion normal, haciéndola mas corta y directa; tipo de notación tienes varias cosas implícitas:
- Por default solo se realiza una acción, el
return
esta implícito y no lleva sus llaves{}
- Estas funciones pueden ser anónimas o no.
- Por default al tener implícito
return
ya no hay necesidad de definir el tipo de la funcion, de cualquier modo se puede hacer.
/**
* Función flecha que no recibe parámetros, retorna un String
*/
mensaje() => "Hola";
/**
* Función que suma dos números y retorna el resultado
*/
suma(int numero1, int numero2) => numero1 + numero2;
/**
* Se define el tipo que retorna, y se realiza la acción necesaria
*/
double calculoFuerza({required double masa, double aceleracion = 9.8}) => masa * aceleracion;
void main() {
print(mensaje());
print(suma(3, 4));
print(calculoFuerza(masa: 15.2));
}
Funciones anidadas (Nested functions
)
Las funciones al ser miembros de primera clase, también podemos declarar funciones dentro de funciones, también llamadas funciones anidadas.
bool topLevel = true;
void main() {
var insideMain = true;
void myFunction() {
var insideFunction = true;
void nestedFunction() {
var insideNestedFunction = true;
print(topLevel);
print(insideMain);
print(insideFunction);
print(insideNestedFunction);
}
}
}
Tipado opcional de funciones
Dart tiene la opción de no tipar las funciones, como sabemos tiene inferencia de tipo; por ende, el infiere el tipo que retorna funcion, en cuestión del valor que estemos retornando.
// Tipando la funcion, sabemos que debemos retornar el tipo String explícitamente
String mensaje(){
return "Hola;
}
// Sin tipar debe inferior el tipo que se retorna, al ver que se retornar una suma de enteros, sabra de manera automática que el tipo que retorna la funcion es int
suma(int a, int b){
return a + b;
}
// Al no tener return la funcion, por default sabemos que no devuelve nada; por ende, es tipo void
mensaje(){ // tipo void
print("Mensaje nuevo")
}
Alcance de variables (Scope)
El scope
o alcance de variables esta definido por las llaves { }
, es decir, toda variable envuelta entre un bloque definido por las llaves, es el ámbito en donde existirá. Fuera de ese bloque, la variable no existe y no se puede tener acceso.
String lenguaje = "Dart"; // esta variable esta en un ÁMBITO GLOBAL, quien sea dentro del archivo puede llamarla y usarla
main(){// ÁMBITO LOCAL DE LA FUNCIÓN MAIN
var lenguajes = ["Python", "Java", "JavaScript", "Lua"]; //existe dentro de toda la función main, fuera de este ámbito no existe
for(int i = 0; i < lenguajes.length; i++){ // ÁMBITO LOCAL DEL CICLO FOR
// la variable i, solo existe dentro del for, por lo tanto lo puede ocupar donde quiera mientras sea dentro del ciclo, porque es el mismo scope
print(lenguajes[i]);
if( i == 0){// ÁMBITO LOCAL DEL IF
String mensaje = "Python es un excelente lenguaje para aprender"; //esta variable solo existe dentro del if, fuera de él desaparece
print(mensaje);
print(lenguaje);
}//termina el if
}// termina el ciclo for
} // termina la función main
Ejemplos
- Realizar una funcion que reciba el nombre, y la edad, e imprimir un saludo con el nombre y diciéndole cuantos años tendrá en 10 años
Ejercicios
- hacer una función que calcule el promedio de 3 calificaciones y retorne el resultado, después usarlo en el main y mandarlo a la pantalla
- Hacer 3 funciones, para la ley de ohms, una para calcular resistencia, otra para corriente y otra para voltaje, implementarla en su código del ejercicio la calculadora de ley de ohm
- Hacer las funciones para calculo de las figuras geométricas, tanto "perímetro" como del "área"
- cuadrado
- rectángulo
- triangulo
- circulo
- después usarlas para hacer la calculadora de todas estas opciones
Mas información en https://dart.dev/language/functions