Функція також може бути параметром для іншої функції:
void doSomething(int function(int, int) doer) {
// виклик переданої функції
doer(5,5);
}
doSomething(&add); // тут використовується глобальна функція
// `add` (додавання), яка мусить мати 2
// параметра типу int
Потім doer
може бути викликана як будь-яка інша нормальна функція.
У наведеному вище прикладі використовується тип function
, який є
вказівником на глобальну функцію. При посиланнях на методи або локальні
функції потрібно використовувати делегати (delegate
). Це вказівник на
функцію, який додатково містить інформацію про її контекст, або -
enclosure, також зване closure (замикання) в інших мовах.
Наприклад, delegate
, який вказує на функцію класу, також містить
вказівник на об'єкт класу. Делегат, отриманий з вкладеної функції,
містить посилання на контекст зовнішньої функції. Однак D компілятор
може автоматично скопіювати ці дані у купу, якщо вважатиме це за
потрібне для безпеки пам'яті. Тоді делегат буде містити посилання на
цю область купи.
void foo() {
void local() {
writeln("local");
}
auto f = &local; // Тип f - delegate()
}
Та сама функція doSomething
яка отримує delegate
виглядала б так:
void doSomething(int delegate(int,int) doer);
Об'єкти delegate
та function
не можна змішувати. Але стандартна
фукнція std.functional.toDelegate
перетворює function
у delegate
.
Оскільки функції можна зберігати, як змінні і передавати в інші функції, було б утомливо давати їм власні імена і визначати їх. Тому у D допускаються безіменні функції і однорядкові лямбди.
auto f = (int lhs, int rhs) {
return lhs + rhs;
};
// Лямбда - всередині перетворіється на:
auto f = (int lhs, int rhs) => lhs + rhs;
Також можливо передавати рядки, як аргументи шаблону у функціональні частини стандартної бібліотеки мови D. Наприклад, вони надають зручний спосіб визначення згортки списку (folding, або інакше reducer):
[1, 2, 3].reduce!`a + b`; // 6
Фукнції-рядки можливі лише для одного чи двох аргументів, коли
використовується a
, як перший та b
, як другий аргументи.