d结构子类化按命名工作

原文

obj.addText(
    ForegroundColor.blue, TextFormat.underline,"链接",
    ForegroundColor.black, ~TextFormat.underline,"普通"
);

它通过变参模板和诸如ForegroundColorBackgroundColor等的各种特化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,ba成员将是透明可用的.

但是,传递给模板时,模板仍按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);
//这是啥意思?

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

posted @   zjh6  阅读(18)  评论(0编辑  收藏  举报  
相关博文:
阅读排行:
· 分享一个免费、快速、无限量使用的满血 DeepSeek R1 模型,支持深度思考和联网搜索!
· 基于 Docker 搭建 FRP 内网穿透开源项目(很简单哒)
· ollama系列01:轻松3步本地部署deepseek,普通电脑可用
· 25岁的心里话
· 按钮权限的设计及实现
点击右上角即可分享
微信分享提示