【问题标题】:D (dlang) passing a lambda function as argumentD (dlang) 将 lambda 函数作为参数传递
【发布时间】:2019-10-04 06:46:02
【问题描述】:

使用 D,我如何将函数(可能是对函数的引用)作为参数传递给其他函数?

import std.stdio : writeln;

class Event {}

class EventTarget
{
    void addEventListener(string eventName, void delegate(Event event) callback)
    {
        // TODO: add to slice to execute later, for now execute directly
        callback();
    }
}

void main()
{
    auto variableFromParentScope = "lorem ipsum";
    auto target = new EventTarget();
    target.addEventListener("load", (Event event) => { writeln(variableFromParentScope, event); }, true);
}

给我错误:

onlineapp.d(10): Error: delegate callback(Event event) is not callable using argument types ()
onlineapp.d(10):        missing argument for parameter #1: Event event
onlineapp.d(18): Error: function onlineapp.EventTarget.addEventListener(string eventName, void delegate(Event event) callback) is not callable using argument types (string, void delegate() @system delegate(Event event) pure nothrow @safe, bool)
onlineapp.d(18):        cannot pass argument __lambda1 of type void delegate() @system delegate(Event event) pure nothrow @safe to parameter void delegate(Event event) callback

我在这里设置了示例:https://run.dlang.io/is/FnQoId


解决方案,在答案的帮助下,我将其修复如下:

import std.stdio : writeln;

class Event {}

class EventTarget
{
    void addEventListener(string eventName, void delegate(Event event) callback)
    {
        // TODO: add to slice to execute later, for now execute directly
        callback(new Event());
    }
}

void main()
{
    auto variableFromParentScope = "lorem ipsum";
    auto target = new EventTarget();
    target.addEventListener(
        "load", 
        (Event event) {
            writeln(variableFromParentScope, event);
        }
    );
}

工作示例:https://run.dlang.io/is/6aDRoU

【问题讨论】:

    标签: function lambda delegates arguments d


    【解决方案1】:

    您为委托使用了错误的语法,您也可以在错误消息中看到它没有预期的类型。

    为了进一步解释,我将向您展示如果您将其扩展为更长的委托形式而不是使用简写 =>,它会如何变化:

    (Event event) => { writeln(variableFromParentScope, event); }
    

    变成

    (Event event) { return { writeln(variableFromParentScope, event); }; }
    

    如您所见,您在实际委托中返回一个没有参数的委托。如果您删除 =>,您的委托将按预期工作。

    您的委托参数的替代有效形式是:

    (event) { ... }
    delegate (Event event) { ... }
    delegate (event) { ... }
    &someMemberMethod // some object member method taking in Event as first parameter
    toDelegate(&someGlobalFunction) // from std.functional
    

    仅当您想返回某些内容时,您才使用=> 箭头。 () => { something } 的用例是委托返回委托(就像委托为给定输入生成委托)

    但您的问题还有一个错误是您在调用参数中使用, true 调用该函数,这使得错误消息非常混乱,并且您没有将事件参数传递给回调,这将是代码sn-p中的另一个错误。

    【讨论】:

    • 谢谢,是的,额外的布尔值从我的其他代码中错误地滑入了那里。我也错过了将 Event 实例传递给回调。现在我对如何在 D 中传递函数有了更多的了解(我主要是一名 JavaScript 开发人员,所以倾向于尝试这种方式)。这使它工作正常: target.addEventListener( "load", (Event event) { writeln(variableFromParentScope, event); } );
    【解决方案2】:

    target.addEventListener("load", (Event event) => { writeln(variableFromParentScope, event); }, true);

    (Args) => {} 是一个 lambda,它返回一个 lambda。

    正确的形式:

    • target.addEventListener("load", (Event event) { writeln(variableFromParentScope, event); }, true);

    • target.addEventListener("load", (Event event) => writeln(variableFromParentScope, event), true);

    【讨论】:

    • 谢谢,是的,在我修复了代码中的其他错误之后,最后一个选项也有效。