Una función también puede ser un parámetro de otra función.
void doSomething(int function(int, int) doer) {
// se llama a la función pasada como parámetro
doer(5,5);
}
doSomething(&add); // se usa la función global `add` y esta
// debe tener dos enteros como parámetros
Se puede llamar a la función doer
como a cualquier otra función.
El ejemplo anterior usa el tipo de dato function
, que no es más que un
puntero a una función local. Se debe usar un delegado (delegate
) en el
momento en que una función miembro o una función local se referencia.
Un delegate
es un puntero a una función que contiene información adicional
sobre su contexto o su enclosure en inglés, de ahí que también se les llame
en otros lenguajes, en inglés, closures. Por ejemplo, un delegate
que
apunte a un método de una clase incluye tanto el puntero a la función como
el puntero al objeto de la clase. Un delegate
creado por una función anidada
incluye un enlace al contexto de la función padre en lugar de a una clase.
Sin embargo, en caso necesario el compilador de D puede hacer automáticamente
una copia de dicho contexto en el heap para garantizar la seguridad de la
memoria. Entonces el delegate
llevará un enlace a dicha zona de memoria.
void foo() {
void local() {
writeln("local");
}
auto f = &local; // f es de tipo delegate()
}
La misma función doSomething
tomando un delegate
como parámetro sería:
void doSomething(int delegate(int,int) doer);
Los objetos delegate
y los objetos function
no se pueden mezclar, pero
la función de la librería estándar std.functional.toDelegate
convierte una function
a un delegate
.
Como las funciones pueden ser guardadas en variables y pasadas como parámetro a otras funciones, puede ser laborioso darles su propio nombre para definirlas. Es por esto que D permite funciones que no tengan nombre y funciones de una sola línea llamadas lambdas.
auto f = (int lhs, int rhs) {
return lhs + rhs;
};
auto f = (int lhs, int rhs) => lhs + rhs; // lambda: internamente convertida a lo de arriba
También es posible pasar cadenas de caracteres como parámetros de plantillas a partes funcionales de la librería estándar de D. Por ejemplo este conveniente modo de definir un folding (también conocido como reductor o reducer en inglés):
[1, 2, 3].reduce!`a + b`; // 6
Las funciones de tipo cadena de caracteres sólo son posibles con uno o dos
parámetros, usando a
como primer argumento y b
como segundo.