gpt4 book ai didi

d - D:查找具有特定属性的所有功能

转载 作者:行者123 更新时间:2023-12-03 13:46:06 26 4
gpt4 key购买 nike

当前是否可以跨模块扫描/查询/迭代具有某些属性的所有函数(或类)?

例如:



source/packageA/something.d:

@sillyWalk(10)
void doSomething()
{
}




source/packageB/anotherThing.d:

@sillyWalk(50)
void anotherThing()
{
}




source/main.d:

void main()
{
for (func; /* All @sillWalk ... */) {
...
}
}

最佳答案

信不信由你,但是的,它确实是……尽管它确实很hacky并且有很多漏洞。代码:http://arsdnet.net/d-walk/

运行将打印:

Processing: module main
Processing: module object
Processing: module c
Processing: module attr
test2() has sillyWalk
main() has sillyWalk


您需要快速浏览 c.db.dmain.d来查看用法。 onEach中的 main.d函数处理帮助函数找到的每个匹配项,这里只是打印名称。在 main函数中,您会看到一个看起来很疯狂的 mixin(__MODULE__)-这是一个狡猾的技巧,可获取对当前模块的引用作为我们迭代的起点。

还要注意, main.d文件的顶部是 module project.main;一行-如果模块名称只是 main,因为它自动不带该声明,则 mixin hack将使该模块混淆功能 main。这段代码真的很脆弱!

现在,将注意力转移到 attr.dhttp://arsdnet.net/d-walk/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)) {
// guards against errors from trying to access private stuff etc.
static if(__traits(compiles, __traits(getMember, a, memberName))) {
alias member = helper!(__traits(getMember, a, memberName));

// pragma(msg, "looking at " ~ 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;
}
}
}
}


首先,我们具有属性定义和一些帮助程序以检测其存在。如果您以前使用过UDA,那么这里没有什么新鲜的-只需扫描属性元组以查找我们感兴趣的类型。

helper模板是简化对 __traits(getMember)的重复调用的技巧-它只是将其别名为更好的名称,同时避免了编译器中的愚蠢的解析错误。

最后,我们有沃克的肉。它循环遍历D的编译时间反射的主力 allMembers(如果您不熟悉,请细读我的D Cookbook https://www.packtpub.com/application-development/d-cookbook的示例章节-“免费示例”链接是有关编译时间反射的章节)

接下来,第一个 static if仅确保我们可以实际获得我们想要获得的成员。否则,尝试获取自动导入的 object模块的私有成员将引发错误。

函数的结尾也很简单-它仅在每个元素上调用 onEach事物。但是中间的地方是魔术:如果它在步行中检测到一个模块(太烂了,但我知道只有这种方法)导入,它将在这里导入,并通过 mixin(module)技巧获得对它的访问。顶层...从而通过程序的导入图重复执行。

如果您玩转,您会发现它实际上是可行的。 (在命令行btw上将所有这些文件一起编译以获得最佳结果: dmd main.d attr.d b.d c.d

但这也有许多限制:


可以进入类/结构成员,但此处未实现。但是非常简单:如果成员是一个类,则也可以递归地进入它。
如果模块与成员共享名称,则可能会导致中断,例如上述带有 main的示例。也可以通过使用带有一些包点的唯一模块名称来解决,这应该没问题。
它不会归入函数本地导入,这意味着可以在程序中使用一个不会被该技巧所利用的函数。即使您愿意使用该语言中的所有技巧,我今天也不知道在D中有任何解决方案。
用UDA添加代码总是很棘手,但是在这里要加倍,因为 onEach是具有作用域的函数。不过,您也许可以在这些事件的处理程序中建立一个全局的委托关联数组: void delegate()[string] handlers; /* ... */ handlers[memberName] = &localHandlerForThis;一种用于在运行时访问信息的事物。
我敢肯定,它也将无法在更复杂的东西上进行编译,我现在只是将其打成一个玩具概念证明。


大多数D代码不是试图像这样遍历导入树,而只是要求您在使用它的单个集合或模块中 mixin UdaHandler!T;,例如每次 mixin RegisterSerializableClass!MyClass;之后。也许不是超级干,但方式更可靠。

编辑:
最初编写答案时,我没有注意到另一个错误:“模块b.d;”。并没有真正被捡起。将其重命名为“模块b;”。可以,但是当包含包装时无效。

ooooh cuz被认为是stringof ..中的“ package mod”,它没有成员。也许如果编译器只是将其称为“ module foo.bar”而不是“ package foo”,我们还是可以开展业务的。 (当然,这对于应用程序编写者来说是不实际的……这有点破坏了该技巧的实用性)

关于d - D:查找具有特定属性的所有功能,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/25555329/

26 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com