0
点赞
收藏
分享

微信扫一扫

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);
//这是啥意思?

为​​各种名字​​​编写​​结构​​​需要少量工作,尽管使用​​插件模板​​​可大部分自动化,但,对​​用户​​​好处是​​显著​​的.


举报

相关推荐

0 条评论