minElement 模板容器如何工作?

How does minElement template containers work?

在下面的函数中,如果我将 a 更改为 kv

void main()
{
    import std.algorithm.searching : minElement;
    import std.stdio : writeln;
    import std.array: byPair;

    long[string] aa = [
        "foo": 5,
        "bar": 10,
        "baz": 2000
    ];
    writeln(aa.byPair().minElement!"a.value"().value); 
}

编译器抛出以下错误消息:

/dlang/dmd/linux/bin64/../../src/phobos/std/functional.d-mixin-215(215): Error: undefined identifier kv /dlang/dmd/linux/bin64/../../src/phobos/std/algorithm/searching.d(1351): Error: template instance std.functional.binaryFun!("kv.value", "a", "b").binaryFun!(Tuple!(string, "key", long, "value"), Tuple!(string, "key", long, "value")) error instantiating /dlang/dmd/linux/bin64/../../src/phobos/std/algorithm/searching.d(1314): instantiated from here: extremum!(__lambda2, "kv.value", MapResult!(__lambda2, Result), Tuple!(string, "key", long, "value")) /dlang/dmd/linux/bin64/../../src/phobos/std/algorithm/searching.d(1398): instantiated from here: extremum!((a) => a, "kv.value", MapResult!(__lambda2, Result)) /dlang/dmd/linux/bin64/../../src/phobos/std/algorithm/searching.d(3550): instantiated from here: extremum!("kv.value", MapResult!(__lambda2, Result)) onlineapp.d(12): instantiated from here: minElement!("kv.value", MapResult!(__lambda2, Result))

但仅使用 "a.value" 参数即可正常编译。 a 是什么意思?

作为函数的字符串参数在 std 文档中随处可见,但它们何时以及如何工作并没有很好的记录。正如您所注意到的,std 采用函数别名参数的模板可以接收字符串而不是实际函数。

然后使用 unaryFun or binaryFun 将此字符串转换为 "real" 函数,后者使用 mixin 或其他一些魔法。他们将参数命名为 ab,您可以使用它们。

正如 Adam D. Ruppe 指出的那样,您也可以像 minElement!(a => a.value)()minElement!((a){ return a.value; }) 一样传递 "normal" functions/delegates,当然参数名称由您决定。

minElement uses unaryFun 将传递的字符串转换为函数。但是,为此它使用字符串混合。这样做的缺点是生成的函数无法访问创建字符串的上下文,因此无法访问那里的变量。

正如unaryFun的文档所说,字符串中的参数名称必须是a。这解释了为什么 kv 失败。

当然,正如 Adam D. Ruppe 所说,您应该改用更新的 lambda 语法 kv => kv.value - 这允许您使用您想要的任何参数名称,并允许访问上下文,让您可以minElement!(kv => kv.value + aa["foo"]) 之类的东西,这对于字符串函数来说根本不可能。

最后,正如您已经注意到的那样,不使用字符串函数的可能最好的原因之一是错误消息。由于从字符串到函数的转换发生在模板堆栈的深处,当实际错误出现在您自己的代码中时,您会得到一个不相关位置的列表,而 lambda 会在易于理解的错误消息中向您准确显示错误所在.