d结构子类化按命名工作
obj.addText(
ForegroundColor.blue, TextFormat.underline,"链接",
ForegroundColor.black, ~TextFormat.underline,"普通"
);
它通过变参模板和诸如ForegroundColor和BackgroundColor等的各种特化arsd.color的通用Color结构的特定子类型来实现该点.下面为前景色的源码.
struct ForegroundColor {
Color color;alias color this;
this(Color c) {
color = c;
}
this(int r, int g, int b, int a = 255) {
color = Color(r, g, b, a);
}
static ForegroundColor opDispatch(string s)() if(__traits(compiles, ForegroundColor(mixin("Color." ~ s)))) {
return ForegroundColor(mixin("Color." ~ s));
}
}
如果重复代码太多,可用mixin template.
这里不必在使用点上写ForegroundColor(Color(r,g,b,a)).
opDispatch简洁地转发静态方法给Color上相同方法,从而允许,如ForegroundColor.white而不是ForegroundColor(Color.white)的调用.
别名本只是转发现有对象上未知方法给成员,并当对象请求子成员类型时也会转发.即,它允许外部成员隐式转换为环境需要的内部成员.
"现有对象"是因为,在别名本生效前,必须已创建该对象.即不能用别名本来转发构造器,也不能调用对象时隐式构造
void foo(ForegroundColor color) {}
Color color;
foo(color);
不会编译.别名本并不构造.
有了别名本,期望Color的函数都可带ForegroundColor,(编译器自动重写func(fg)为func(fg.color)),并且Color上其他成员也可通过ForegroundColor来访问.如,r,g,b和a成员将是透明可用的.
但是,传递给模板时,模板仍按ForegroundColor,而不是Color对待!类似地,函数可在ForegroundColor而不是在Color上单独重载(只要类型是静态已知的.与类不同,Color上无(ForegroundColor)动态强制转换.记住,编译器重写为成员访问.因而,该函数只看到成员,而不知道谁持有它.).
由于函数可在编译时区分差异,可用反省!看看addText.
忽略细节,只看函数的大概:
void addText(Args...)(Args args) {
foreach(arg; args) {
static if(is(typeof(arg)==Something)){
} else static if /* ... */ {
}
}
}
可用foreach遍历变参(也叫元组或AliasSeq),并单独检查每个参数类型并响应.
addText结合分析类型及检查值,来确定操作.如果看到简单风格,则会打开它.用~来翻转.如果看到Color的特化,它会用该类型来了解它是否应更改前景或其他颜色值.
还可在opAssign或其他属性中用此模式,来根据赋值类型操作.
也可重载函数来完成它,但循环更易处理更多组合.
void addText(ForegroundColor color, string text) {}
void addText(BackgroundColor color, string text) {}
void addText(ForegroundColor color, BackgroundColor bg, string text) {}
void addText(ForegroundColor color, BackgroundColor bg, TextFormat fmt, string text) {}
void addText(string text);
...
//仍用静断
使用循环或重载,可用相同模式可模拟命名参数.为特定数据片定义特定类型,可强制调用点使用该名,从而提供类型安全命名参数文档.用重载或循环,可按任意顺序使用它们,包括必需的,可选的或默认值.
struct Size { int w; int h; }
struct Point { int x; int y; }
struct PointUpperLeft { Point p; alias p this; this(int x, int y) { p = Point(x, y); } }
struct PointLowerRight { Point p; alias p this; this(int x, int y) { p = Point(x, y); } }
drawRectangle(Point(0, 0), Size(10, 10), ForegroundColor.red);
drawRectangle(PointUpperLeft(0, 0), PointLowerRight(10, 10), ForegroundColor.red);
drawRectangle(0, 0, 10, 10, 255, 0, 0);
//这是啥意思?
为各种名字编写结构需要少量工作,尽管使用插件模板可大部分自动化,但,对用户好处是显著的.
浙公网安备 33010602011771号