Skip to content

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.

funcion funcion

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

tipoQueDevuelve nombreDeFuncion (tipo argumento1, tipo argumento2, ...){
    cuerpo de la función o
    todas las acciones que ocurren en la función

    Al final va "return" con el dato que devuelve (o referencia)
}

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.

funcion1.dart
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.

funcion2.dart
/**
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.

funcion3.dart
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);
}
Podemos crear una funcion que reciba un callback para que realice cierta acción. Esto es algo común con funciones asíncronas.

/**
 * 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 scopeo 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

  1. 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
  2. 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
  3. 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