d为啥要用全名
原文
有个把标准库的std.traits.fullyQualifiedName转化为__traits(fullyQualifedName)的请求.因为Phobos实现扩展了很多模板,所以想法是通过在编译器中实现它来减少编译时间.然而,亚当认为不应使用它,定义很差,且很容易错误地元编程.
因此问题是:你是否用std.traits.fullyQualifiedName,如果用,用它来做什么?
相关链接:1,2
我不用全名,有带整合属性的__traits和typeid对我已足够了.
class S
{
short n;
alias n this;
this(short n) { this.n = n; }
}
void print(alias T)()
{
import std.stdio : writeln;
TypeInfo name = typeid(T);
name.writeln;
import std.traits : fullyQualifiedName;
fullyQualifiedName!T.writeln;
T test = [ new S(41), new S(42) ];
__traits(getPointerBitmap, S).writeln(": ", test);
}
void main() {
alias arrS = const S[];
print!arrS;
class S { short s; }
auto test = new S;
assert(__traits(getPointerBitmap, S) == [32, 8]);
assert(is(
typeof(S.s) == short)
);
} /*
const(const(onlineapp.S)[])
const(onlineapp.S[])
[18, 0]: [const(onlineapp.S), const(onlineapp.S)] //*/
哦,还有该
struct Str
{
alias ToString this;
size_t s;
string ToString() const
{
import std.conv : text;
return text(s);
}
}
enum Params { width= 100 }
auto String = Str(Params.width);
import std.conv;
void main()
{
string[] data;
data ~= __traits(identifier, String);
data ~= typeof(String).stringof;
data~= String;
data ~= Params.width.to!string;
data.writeln; // ["String", "Str", "100", "width"]
}
D给了我创造大世界的一切.
亚当:不应使用fullyQualifiedName来查找符号
但是我坚信他错了,他说它不应有,它应该,它需要有,它是基本自省能力.
我在后两个方面使用它:
1)唯一标识一个类型(注册类型来序化,或传递到哈希函数等)(.a).
2)对调试来说,打印效果很好..b.
:.a.
编译器使用.mangleof来实现该目的,而druntime使用typeid().全名只是mangleof的更大但并不独特的表示.
:.b
很简单就可实现(包括非常快地切换到mangleof).
那么为什么Phobos的实现会如此复杂呢?嗯,有些是不必要的复杂,但大部分是与各种不同类型的模板参数有关(其余大部分是因为函数重载).这些参数也可从mangleof中提取,我在github线程中说过,但很多时候这些参数损害了可读性.
对调试,你很可能更愿意部分全名+源码位置,它更能帮助调试:
random.d:1081 std.random.Mt19937
//对比
std.random.MersenneTwisterEngine!(uint, 32, 624, 397, 31, 0x9908b0df, 11, 0xffffffff, 7, 0x9d2c5680, 15, 0xefc60000, 18, 1_812_433_253)
(标准库和PR中的特征选择了后者.)
现在,我承认这有点不公平,因为编译器再也不公开别名了.但:
random.d:1081 std.random.MersenneTwisterEngine
不带参数更有利于调试.这是简单示例.
在PR线程中,我提出:
structFromTable!(import("db.sql"), "MyTable");
源码中的这种表示还算不错.定义点非常可读.假定转储全名到屏幕上,有几万字节.这有用吗?
取别名的trait会更有用!至少全局别名是这样;像
template a(alias A) {}
此局部变量总是返回不是很有趣的A,但是如果在外部域中别名名字,这确实是有价值的信息.
现在,我承认模板参数有时是有用的:
struct Thing {
Nullable!int a;
Nullable!string b;
}
如果只按'std.typecons.Nullable'打印了类型,你就遗漏了.怎么知道哪个值得打印?要看情况,这表明最好用库代码来完成.
同时,编译器还可用它的知识来消歧.
除非域中有另一个Nullable,可打印它为Nullable或Nullable!int,否则此时,它打印带模块名的std.typecons.Nullable来澄清.对错误消息,编译器有知识和现有代码.因此,公开它可能会有些价值.
在D类外创建网络API和用户接口?没有全名.
用D声明创建脚本语言绑定?没有全名.
从D接口创建动态库加载器?没有全名.
在D和Java或C#代码之间创建双向桥梁?无全名.
自定义单元测试?无全名.
从XML映射D模块到实例化类?没有全名.
自定义事件循环消息框,接受类型并分发它们?不需要全名.
根据具体情况使用.mangleof或typeid(),这就是dmd和druntime干的.
从标识中产生部分全名,一般它更可读.这就是dmd干的.
:避免因为生成的代码中导入而导致名字冲突
使用本地名,这不是问题.如果看到冲突,表明你正在与语言斗争,而不是使用更好方法来合作.
浙公网安备 33010602011771号