Делегати

Функції як аргументи

Функція також може бути параметром для іншої функції:

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, як другий аргументи.

Додатково

rdmd playground.d