En Dart, las funciones también son objetos, lo que lo diferencia un poco de otros lenguajes de programación.
Las funciones son objetos de primera clase
Dart es un lenguaje totalmente orientado a objetos: las propias funciones son objetos, con el tipo Function.
Se pueden asignar a variables y pasarse como argumentos a otras funciones;
Las instancias de clase se pueden invocar directamente como si fueran funciones
1 Definición estándar de función
// Declaración completa con anotaciones de tipo de retorno y parámetros
bool isNoble(int atomicNumber) {
return _nobleGases[atomicNumber] != null;
}
Lenguaje del código: Dart (dart)
Ejemplo completo
// Tabla de correspondencia de números atómicos de gases nobles
final Map<int, String> _nobleGases = {
2: 'He',
10: 'Ne',
18: 'Ar',
36: 'Kr',
54: 'Xe',
86: 'Rn',
};
// Declaración completa con tipo de retorno y tipos de parámetros
// El tipo int no admite valores null; usa int? para aceptar parámetros anulables
bool isNoble(int? atomicNumber) {
return _nobleGases[atomicNumber] != null;
}
void main() {
print(isNoble(null)); // null no es una clave del mapa → false
print(isNoble(2)); // Coincide con un gas noble → true
print(isNoble(9)); // Sin coincidencia → false
print(isNoble(86)); // Coincide con un gas noble → true
}
Lenguaje del código: Dart (dart)
false
true
false
trueLenguaje del código: JavaScript (javascript)
2 Omitir anotaciones de tipo
La guía de estilo Effective Dart establece que las APIs públicas visibles externamente deben llevar anotaciones de tipo explícitas y completas.
Se pueden omitir las anotaciones de tipo en funciones privadas internas
Ejemplo
final Map<int, String> _nobleGases = {
2: 'He',
10: 'Ne',
18: 'Ar',
36: 'Kr',
54: 'Xe',
86: 'Rn',
};
isNoble(atomicNumber) {
return _nobleGases[atomicNumber] != null;
}
void main() {
print(isNoble(null)); // null no es una clave del mapa → false
print(isNoble(2)); // Coincide con un gas noble → true
print(isNoble(9)); // Sin coincidencia → false
print(isNoble(86)); // Coincide con un gas noble → true
}
Lenguaje del código: Dart (dart)
En el ejemplo anterior, la función isNoble no especifica el tipo de retorno bool ni el tipo de parámetro int?, pero funciona perfectamente.
Cuando no escribes tipos, Dart realiza una inferencia de tipos automática:
- Parámetro
atomicNumber: Sin tipo explícito → se infiere comodynamic(tipo dinámico, acepta cualquier valor: números, cadenas, null) - Valor de retorno: Sin anotación de tipo al principio → Dart deduce que el tipo de retorno es
boola partir de la expresión trasreturn, sin escribirlo en el código
¿Por qué las APIs públicas deben llevar tipos explícitos obligatoriamente?
Legibilidad: Los desarrolladores que llamen tu función ven inmediatamente los tipos de entrada y salida, sin tener que leer el código interno para adivinar;
Seguridad de tipos: El tipo dynamic desactiva la comprobación estática; pasar tipos incorrectos no genera errores de compilación y suele provocar fallos en ejecución;
Intellisense del IDE: Las anotaciones de tipo activan el autocompletado y los avisos de parámetros en el editor; sin tipos, el IDE no puede ofrecer sugerencias precisas.
¿Cuándo se pueden omitir las anotaciones de tipo?
Solo recomendado para código privado local: funciones usadas exclusivamente dentro del archivo actual y nunca invocadas desde fuera.
Sintaxis abreviada de flecha (=>)
Si el cuerpo de la función (código entre {}) solo contiene una única expresión de retorno, puedes usar la sintaxis de flecha.
Ejemplo
bool isNoble(int atomicNumber) => _nobleGases[atomicNumber] != null;
Lenguaje del código: Dart (dart)
=> exprequivale a{ return expr; };- Solo se pueden escribir expresiones entre la flecha y el punto y coma; sentencias como
ifestán prohibidas (usa operadores ternarios en su lugar).
// Tabla de correspondencia de números atómicos de gases nobles
final Map<int, String> _nobleGases = {
2: 'Helio',
10: 'Neón',
18: 'Argón',
36: 'Kriptón',
54: 'Xenón',
86: 'Radón',
};
// Función abreviada de flecha: retorna directamente una expresión en una línea, equivalente a funciones de bloque con return
bool isNoble(int atomicNumber) => _nobleGases[atomicNumber] != null;
void main() {
// Probar gases nobles existentes
print(isNoble(2)); // true
print(isNoble(18)); // true
// Probar elementos comunes
print(isNoble(6)); // false (Carbono)
print(isNoble(99)); // false (sin elemento coincidente)
}
Lenguaje del código: Dart (dart)

Parámetros
Las funciones admiten parámetros posicionales obligatorios, seguidos de una única opción: parámetros con nombre o parámetros posicionales opcionales — no se pueden mezclar ambos tipos.
Las comas finales , están permitidas al definir o invocar parámetros para mejorar la legibilidad del código.
1. Parámetros con nombre Named parameters
Delimitados con {}, son opcionales por defecto; agrega required para obligar a enviarlos.
1) Parámetros con nombre anulables básicos (sin valor por defecto, su valor predeterminado es null, el tipo debe marcarse con ? para ser anulable)
void enableFlags({bool? bold, bool? hidden}) {}
// Especifica explícitamente los nombres de los parámetros al invocar
enableFlags(bold: true, hidden: false);
Lenguaje del código: Dart (dart)
Ejemplo completo
/// Activar banderas de estilo de texto: negrita, oculto
void enableFlags({bool? bold, bool? hidden}) {
print('Negrita: $bold, Oculto: $hidden');
}
void main() {
// Enviar todos los parámetros con nombre
enableFlags(bold: true, hidden: false);
// Enviar solo un parámetro con nombre, el otro queda null
enableFlags(bold: true);
// Enviar solo hidden
enableFlags(hidden: true);
// No enviar ningún parámetro, ambos valores son null
enableFlags();
}
Lenguaje del código: Dart (dart)
Resultado de ejecución
D:\dartdemo\firstdart>dart run
Building package executable...
Built firstdart:firstdart.
Negrita: true, Oculto: false
Negrita: true, Oculto: null
Negrita: null, Oculto: true
Negrita: null, Oculto: nullLenguaje del código: JavaScript (javascript)
2) Establecer valores por defecto constantes en tiempo de compilación (no hace falta marcar el tipo como anulable al existir un valor predeterminado)
void enableFlags({bool bold = false, bool hidden = false}) {}
enableFlags(bold: true); // hidden usa automáticamente false
Lenguaje del código: Dart (dart)
Ejemplo
/// Activar banderas de estilo de texto: negrita, oculto
void enableFlags({bool bold = false, bool hidden = false}) {
print('Negrita: $bold, Oculto: $hidden');
}
void main() {
enableFlags();//Sin parámetros enviados, ambos usan el valor por defecto false → Negrita: false, Oculto: false
}
Lenguaje del código: Dart (dart)
3) Parámetros con nombre obligatorios con required (Nota: Muy usados en constructores de componentes Flutter). El ejemplo siguiente es código Flutter; aprende más en los tutoriales de Flutter.
const Scrollbar({super.key, required Widget child});
// Los parámetros required también aceptan tipos anulables
const Scrollbar({super.key, required Widget? child});
Lenguaje del código: Dart (dart)
Dart no obliga a colocar los parámetros con nombre al final de la lista; se pueden insertar en cualquier posición de la lista de parámetros
repeat(times: 2, () {})Lenguaje del código: CSS (css)
2. Parámetros posicionales opcionales Optional positional parameters
Delimitados con [], su valor es null si se omiten; se pueden definir valores por defecto constantes.
// Sin valor por defecto, tipo marcado con ?
String say(String from, String msg, [String? device]) {
var result = '$from says $msg';
if (device != null) result = '$result with a $device';
return result;
}
assert(say('Bob', 'Howdy') == 'Bob says Howdy');
assert(say('Bob', 'Howdy', 'smoke signal') == 'Bob says Howdy with a smoke signal');
Lenguaje del código: Dart (dart)
Ejemplo completo
// [String? device] parámetro posicional opcional sin valor por defecto, vale null si se omite
String say(String from, String msg, [String? device]) {
var result = '$from says $msg';
if (device != null) {
result = '$result with a $device'; //Agregar información del dispositivo al mensaje si device no es null
}
return result;
}
void main() {
// Omitir el tercer parámetro opcional
String res1 = say('Bob', 'Howdy');
print(res1);
// Enviar el tercer parámetro posicional opcional
String res2 = say('Bob', 'Howdy', 'smoke signal');
print(res2);
// Enviar manualmente null al parámetro opcional
String res3 = say('Alice', 'Hi', null);
print(res3);
}
Lenguaje del código: Dart (dart)
Establecer valores por defecto:
String say(String from, String msg, [String device = 'carrier pigeon']) {
return '$from says $msg with a $device';
}
assert(say('Bob', 'Howdy') == 'Bob says Howdy with a carrier pigeon');
Lenguaje del código: Dart (dart)
Ejemplo completo
// Parámetro posicional opcional con valor por defecto carrier pigeon (paloma mensajera)
String say(String from, String msg, [String device = 'carrier pigeon']) {
return '$from says $msg with a $device';
}
void main() {
// Omitir el tercer parámetro opcional, usa automáticamente el valor por defecto carrier pigeon
String res1 = say('Bob', 'Howdy');
print(res1); //Bob says Howdy with a carrier pigeon
// Enviar dispositivo personalizado para sobrescribir el valor por defecto
String res2 = say('Bob', 'Howdy', 'smoke signal');
print(res2); //Bob says Howdy with a smoke signal
String res3 = say('Alice', 'Hello', 'mobile phone');
print(res3); // Alice says Hello with a mobile phone
String res4 = say('Jack', 'Tom', 'website foxdevelop.com');
print(res4); // Jack says Tom with a website foxdevelop.com
}
Lenguaje del código: Dart (dart)
Resultado de ejecución
Built firstdart:firstdart.
Bob says Howdy with a carrier pigeon
Bob says Howdy with a smoke signal
Alice says Hello with a mobile phone
Jack says Tom with a website foxdevelop.comLenguaje del código: JavaScript (javascript)
Función de punto de entrada main ()
Cada programa Dart debe tener una función main() de nivel superior; es el único punto de ejecución del programa.
- Versión básica sin parámetros
void main() {
print('Hello, welcome to foxdevelop.com!');
}
Lenguaje del código: Dart (dart)
Hello, welcome to foxdevelop.com!Lenguaje del código: CSS (css)
- Programa de línea de comandos que recibe argumentos de lanzamiento
// Comando de ejecución: dart run firstdart.dart 1 test
void main(List<String> arguments) {
print(arguments); // [1, test]
}
Lenguaje del código: Dart (dart)
Usa la librería oficial args para analizar argumentos de línea de comandos complejos.
Reemplaza firstdart.dart anterior por el nombre de tu archivo Dart

Las funciones como objetos de primera clase First-class objects
1. Pasar funciones como parámetros
void printElement(int element) => print(element);
var list = [1, 2, 3];
list.forEach(printElement); // Pasar la función directamente
Lenguaje del código: Dart (dart)
Ejemplo completo
void main() {
void printElement(int element) => print(element);
var list = [1, 2, 3];
list.forEach(printElement); // Pasar la función directamente
}
Lenguaje del código: Dart (dart)
Salida
1
2
3
2. Asignar funciones anónimas a variables
void main() {
var loudify = (msg) => '!!! ${msg.toUpperCase()} !!!';
print(loudify('hello')); //!!! HELLO !!!
}
Lenguaje del código: Dart (dart)
Tipos de función Function Type
Puedes declarar explícitamente los tipos de variables de función
Formato: TipoRetorno Function(ListaParametros, {ParametrosConNombre})
void greet(String name, {String greeting = 'Hello'}) => print('$greeting $name!');
// Declarar variable de tipo función
void Function(String, {String greeting}) g = greet;
g('Dash', greeting: 'Howdy');
Lenguaje del código: Dart (dart)
Usa typedef para crear alias de tipos de función, mejorar la reutilización y legibilidad.
{String greeting}) → Un parámetro con nombre greeting de tipo String
void main() {
void greet(String name, {String greeting = 'Hello'}) => print('$greeting $name!');
// Declarar variable de tipo función
void Function(String, {String greeting}) g = greet;
g('Jack', greeting: 'Howdy');
}
Lenguaje del código: Dart (dart)
Salida
Howdy Jack!
Funciones anónimas (Lambda / Closure cierre léxico)
Funciones sin nombre definido, dos formas de escritura:
- Sintaxis de bloque (varias líneas)
void main() {
const list = ['apples', 'bananas'];
var uppercaseList = list.map((item) {
return item.toUpperCase();
}).toList();
print(uppercaseList);
}
Lenguaje del código: Dart (dart)
(item) { return item.toUpperCase(); } en el código anterior es una función anónima (lambda)
Salida: [APPLES, BANANAS]
- Abreviatura de flecha (expresión de una sola línea)
void main() {
const list = ['fox', 'develop','foxdevelop.com'];
var uppercaseList = list.map((item) => item.toUpperCase()).toList();
uppercaseList.forEach((item) => print('$item: ${item.length}'));
}
Lenguaje del código: Dart (dart)
Salida
FOX: 3
DEVELOP: 7
FOXDEVELOP.COM: 14Lenguaje del código: HTTP (http)
Ámbito léxico Lexical scope
Dart usa un ámbito léxico estático: el ámbito de una variable se define por la jerarquía de llaves del código, y los ámbitos internos pueden acceder a todas las variables de los ámbitos externos.
bool topLevel = true;
void main() {
var insideMain = true;
void myFunction() {
var insideFunction = true;
void nestedFunction() {
var insideNestedFunction = true;
// Todas accesibles
assert(topLevel && insideMain && insideFunction && insideNestedFunction);
}
}
}
Lenguaje del código: Dart (dart)
Cierres léxicos Lexical closures
Cierre: un objeto función puede capturar y conservar variables del ámbito externo, y acceder a ellas incluso después de abandonar el ámbito original.
Function makeAdder(int addBy) {
// Capturar variable externa addBy
return (int i) => addBy + i;
}
void main() {
var add2 = makeAdder(2);
var add4 = makeAdder(4);
assert(add2(3) == 5);
assert(add4(3) == 7);
}
Lenguaje del código: Dart (dart)
Desglose paso a paso del flujo de ejecución anterior
Paso 1: var add2 = makeAdder(2);
- Ejecutar
makeAdder, pasaraddBy = 2 - Crear función anónima:
(int i) => 2 + i - Asignar esta función a la variable
add2. En este momento add2 es un objeto función cuyo cuerpo es(int i) => 2 + i; recibe un entero i y retorna i+2 - La ejecución de la función
makeAdderfinaliza, pero la función anónima recuerda permanentementeaddBy=2
Paso 2: var add4 = makeAdder(4);
- Ejecutar
makeAdderde nuevo, pasaraddBy = 4 - Crear una nueva función anónima totalmente independiente:
(int i) => 4 + i - Asignar a
add4, que almacena su propia copia independiente deaddBy=4sin interferir con add2. Es decir, el valor addBy se guarda por separado en los dos objetos función add2 y add4, uno guarda 2 y el otro 4
- La llamada a
makeAdder(2)genera un cierre independiente con un valor vinculado únicoaddBy = 2, asignado aadd2; - La llamada a
makeAdder(4)genera un cierre totalmente nuevo y separado con un valor vinculado únicoaddBy = 4, asignado aadd4; add2yadd4son objetos función completamente separados, cada uno almacena en privado su variableaddBycapturada sin interferirse mutuamente.
Paso 3: Invocar add2(3)
Ejecutar función interna: 2 + 3 = 5, la aserción se cumple
Paso 4: Invocar add4(3)
Ejecutar función interna: 4 + 3 = 7, la aserción se cumple
Tear-offs de función
Si invocas una función/método sin paréntesis, creas un tear-off (cierre ligero), que reemplaza las lambdas anónimas escritas manualmente para un código más limpio.
Esta es la sintaxis recomendada; solo tienes que pasar la función directamente.
var charCodes = [68, 97, 114, 116];
var buffer = StringBuffer();
charCodes.forEach(print); // Tear-off de función
charCodes.forEach(buffer.write); // Tear-off de método
Lenguaje del código: Dart (dart)
Sintaxis equivalente más verbosa
charCodes.forEach((code) => print(code));
charCodes.forEach((code) => buffer.write(code));
Lenguaje del código: Dart (dart)
Comprobación de igualdad de funciones
- Funciones de nivel superior, métodos estáticos:
==devuelve true si los nombres de función coinciden exactamente; - Métodos de instancia: solo los tear-offs vinculados a la misma instancia de objeto se consideran iguales.
void foo() {}
class A {
static void bar() {}
void baz() {}
}
void main() {
var x = foo;
assert(foo == x);
x = A.bar;
assert(A.bar == x);
var v = A(), w = A(), y = w;
x = w.baz;
assert(y.baz == x); // Misma instancia → iguales
assert(v.baz != w.baz); // Distintas instancias → no iguales
}
Lenguaje del código: Dart (dart)
Valores de retorno Return values
- Todas las funciones tienen valor de retorno: si no existe un
returnexplícito, se añade implícitamentereturn null;al final
foo() {}
assert(foo() == null);
Lenguaje del código: Dart (dart)
- Retornar varios valores: usar tuplas Record
(String, int) foo() {
return ('something', 42);
}
Lenguaje del código: Dart (dart)
Accesores Getter & Setter
Leer o asignar cualquier propiedad equivale fundamentalmente a llamar su getter o setter; las variables normales generan automáticamente accesores implícitos, también puedes definirlos explícitamente a mano.
Ventaja: el código externo accede uniformemente con .nombrePropiedad, la lógica interna se puede modificar en cualquier momento sin actualizar el código llamante externo.
String _secret = 'Hello';
// Getter para lectura
String get secret {
print('Se invoca el getter');
return _secret.toUpperCase();
}
// Setter para asignaciones
set secret(String newMsg) {
print('Se invoca el setter');
if (newMsg.isNotEmpty) _secret = newMsg;
}
void main() {
print(secret); // Lectura, activa getter → HELLO
secret = 'Dart is fun'; // Asignación, activa setter
print(secret); // DART IS FUN
}
Lenguaje del código: Dart (dart)
* Generadores Generators
Generan secuencias de forma diferida bajo demanda, dos variantes: sincrónico y asincrónico, usan yield para emitir valores.
- Generador sincrónico
sync*, retornaIterable
Iterable<int> naturalsTo(int n) sync* {
int k = 0;
while (k < n) yield k++;
}
Lenguaje del código: Dart (dart)
- Generador asincrónico
async*, retornaStream
Stream<int> asyncNaturalsTo(int n) async* {
int k = 0;
while (k < n) yield k++;
}
Lenguaje del código: Dart (dart)
- Optimización de generadores recursivos
yield*(delega a otro generador para mejorar el rendimiento)
Iterable<int> naturalsDownFrom(int n) sync* {
if (n > 0) {
yield n;
yield* naturalsDownFrom(n - 1);
}
}
Lenguaje del código: Dart (dart)
Function