d的内省设计(dbi)
内省设计
原地址
作者:H.S.Teoh,这是中国人.
基本理念很简单,但结果却很强大.传统代码:
auto myFunc(T data) { ... }
这里T为具体整/浮/构等.然而该函数在实现中不必依赖T的所有细节.它可能只需要.前/.空的函数.
因而,这里可抽象为只要有带期望语义的.前/.空的函数的任意类型.现在是:
auto myFunc(T)(T data) {
... //利用`.前/.空的`函数.
}
这是模板函数.而内省设计更进一步,假定.空的非必要,其只是可优化效率.因而可让无.空的类型传进来.现在,可用静如来检查它.
auto myFunc(T)(T data) {
static if (.../*如有空的*/) {
... // 利用`空的/前`函数
} else {
... // 无`空的`的实现.
}
}
现在,可利用两类类型:有空的/前类型或有前类型.
同样,不必限制在存在字段,也可为编译时可内省的任意属性.如基于类型大小用静如来切换实现,或如何为大量实例最佳分配内存,或根据用定属来改变函数行为.
看起来作用不大,但我们可用静如来扩大适用函数的类型.静如越多适用类型越多.让函数适应调用者需求.
传统中,是每个构/类有个序化方法.这很烦人.现在:
void save(S,T)(S storage, T data) {
static if (is(T == struct)) {
... // 序化构
} else static if (is(T == class)) {
... // 序化类
} else if (is(T == U[], U)) {
... // 序化数组
} else if (is(T : int)) {
... // 序化整类
}
... // 等等
else static assert(0, "不能序化" ~ T.stringof~"类型");
}
现在,这样使用:
S data;
storage.save(data);
//序化S构
int data;
storage.save(data);
//序化整
S[] data;
storage.save(data);
//序化数组
超级简单.只改类型,连data都不必改.自动适应.
如果,我想让串与数组不一样呢,可在数组的静如块前加处理串的静如块.
void save(S,T)(S storage, T data) {
static if ...
... else if (is(T == string)) {
... // 特殊处理串.
} else if (is(T == U[], U)) {
... // 通用数组
} else ...
}
但如果想,特殊处理特殊类型呢?如排除某些字段.如排除下次可重新计算的存储缓存的字段.此时,就可用用定属.用用定属属性标记不想保存的字段.
struct DontSerialize {}
struct MyStruct {
int i; // 保存
float f; // 保存
@DontSerialize string s; // 不保存
}
void save(S,T)(S storage, T data) {
...
static if (is(T == struct)) {
foreach (field; allMembers!T) {
// 跳过`DontSerialize`标记字段
static if (!hasUDA!(mixin("data."~field), DontSerialize)) {
... // 这里序化.
}
}
}
...
}
传统方法,需要黑名单/标志,而基于内省设计,都不需要.
MyStruct[] data;
storage.save(data);
//使用代码如前.
只需要用用定属标记构中字段.并添加一个处理用定属的静如块,就行了.不需要大规模重构,就行了.
利用用定属,还可做很多.如用不同用定属标记不同序化机制.如可压缩数据.不必保存数据,等等.而保存的接口完全一样.仍然是:
storage.save(data);
不必改动调用保存的代码.只需要标记类型定义,一切搞定.
这就是内省设计的力量.
浙公网安备 33010602011771号