d查找特定属性的所有函数
Processing: module main
Processing: module object
Processing: module c
Processing: module attr
test2() has sillyWalk
main() has sillyWalk
需要快速查看c.d,b.d和main.d以了解其用法.main.d的onEach函数处理每次帮助函数找到的命中,这里只是打印名.在main函数中,你会看到一个疯狂mixin(__MODULE__),用来按迭代起点取当前模块的引用.
注意,main.d文件顶部有module project.main;一行,如果模块名仅为main,那么mixin黑客会混淆main模块与函数.
现在,注意attr.d.
module attr;
struct sillyWalk { int i; }
enum isSillyWalk(alias T) = is(typeof(T) == sillyWalk);
import std.typetuple;
alias hasSillyWalk(alias what) = anySatisfy!(isSillyWalk, __traits(getAttributes, what));
enum hasSillyWalk(what) = false;
alias helper(alias T) = T;
alias helper(T) = T;
void allWithSillyWalk(alias a, alias onEach)() {
pragma(msg, "Processing: " ~ a.stringof);
foreach(memberName; __traits(allMembers, a)) {
// 保证避免错误
static if(__traits(compiles, __traits(getMember, a, memberName))) {
alias member = helper!(__traits(getMember, a, memberName));
// pragma(msg, "查看" ~ memberName);
import std.string;
static if(!is(typeof(member)) && member.stringof.startsWith("module ")) {
enum mn = member.stringof["module ".length .. $];
mixin("import " ~ mn ~ ";");
allWithSillyWalk!(mixin(mn), onEach);
}
static if(hasSillyWalk!(member)) {
onEach!member;
}
}
}
}
首先,有属性定义和一些帮助器来检测它的存在.只需扫描属性元组来查找感兴趣类型.
helper模板是缩写重复__traits(getMember)调用的技巧,它只是别名为更好名,同时避免编译器中出现愚蠢的解析错误.
最后,有了步行者.它循环了allMembers.
接着,第一个static if只是确保可真正获得想要获得成员.没有它,它会在获取自动导入object模块的私有成员时抛错误.
函数结尾也很简单,它只是在每个元素上调用onEach.中间有点神奇:它检测到导入模块,在此导入,通过mixin(module)顶层技巧访问它,然后通过导入图递归.
dmd main.d attr.d b.d c.d
也有些限制:
1,可以进入类/结构成员,但这里没有实现.不过非常简单:如果成员是类,也只需递归进入它.
2,如果模块与成员共享名,则可能会中断,如main示例.用带有一些包点的唯一模块名来解决问题它.
3,它不会下降到函数本地导入,
使用UDA添加代码总是很麻烦,在此更是,因为onEach是具有域的函数.不过,也许可构建全局关联闭包
void delegate()[string] handlers;
/* ... */
handlers[memberName] = &localHandlerForThis;
大多数D代码,不需要如上遍历导入树,只是要求你,在使用它的单个聚集或模块中:
mixin UdaHandler!T;
或在每个之后:
mixin RegisterSerializableClass!MyClass;
浙公网安备 33010602011771号