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
或其他一些魔法。他们将参数命名为 a
和 b
,您可以使用它们。
正如 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 会在易于理解的错误消息中向您准确显示错误所在.
在下面的函数中,如果我将 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
或其他一些魔法。他们将参数命名为 a
和 b
,您可以使用它们。
正如 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 会在易于理解的错误消息中向您准确显示错误所在.