0
点赞
收藏
分享

微信扫一扫

d实验新异常


​​原文​​​ 串不好,应​​用​​变量.​​很容易​​创建新类型.如​​std.algorithm​​中管道一样,隐式实例化模板的​​返回值​​.
我构建了​​arsd.exception​​模块,新​​异常​​重点是改进​​enforce​​.

用法

import exception2;

enum MyError;
enum OtherError;

void main() {
int a;
try {
throw Exception2!MyError(a, "更多信息");
} catch(Exception2!(OtherError) e) {
// 不会抓它,因为它是另一个错误
import std.stdio;writeln("wrong");
} catch(Exception2!(MyError, int) e) {
// 会抓!
import std.stdio;writeln("CAUGHT!");
writeln(e);
}
}

我抛了​​整/串​​​,但只抓了​​整​​​.想法细节只是​​进一步​​​特化,可根据是否​​感兴趣​​​来处理它们.如果不关心​​附加数据​​​,可只​​catch(Exception2!MyError)​​​.
或静态列举​​​MyError​​​构中​​数据​​​,而不是用​​MyError​​​来枚举.另一方面,可丢弃所有​​命名空间类型​​​的区分,而只使用​​Exception2!("somestring",data)​​.

import exception2;
void main() {
int a;

try {
//串错误类型而不是命名空间的D类型仍可附加信息
throw Exception2!"foo bar"(a);
} catch(Exception2!"foo bar") { //按串抓
import std.stdio;
writeln("caught");
}
}

我不大喜欢,​​串​​​不能区分​​不同库​​​.而使用​​enum​​​,可通过​​模块导入和命名空间​​​规则区分.
优点是可​​​不提前​​​声明,可在​​抛点​​​声明,并在​​抓​​​点确认.我不大喜欢这种风格,但与​​throw new Exception("一些串")​​​一样方便,且可附加数据.
你可能反驳说,声明新类,并用​​​mixin template​​​.声明​​结构​​​,​​枚举​​​,并在​​那里​​​声明​​相关数据​​​.好处不大.
我要说,​​​枚​​​声明,得到了​​异常族的静态列表​​​,然后根据需要​​添加​​​数据.
考虑​​​InvalidValue​​​族,附加信息,给了​​int valueGiven, int maxValue​​​,或​​int valueGiven, int minValue, int maxValue​​​,或​​string valueGiven, string expectedPattern​​​.一个族,可合理地​​附加​​​不同​​值​​​.
这,也是为何​​​需要​​​结构化数据.
如果得到两个​​​int​​​值,哪个是​​valueGiven​​​,哪个是​​maxValue​​​?还是给出了​​两个值​​​(如​​矩阵坐标​​​)?
用该机制,你可

throw Exception2!InvalidValue(MyStruct(structured, information, here);

别人可

catch(Exception2!InvalidValue)
//或
catch(Exception2!(InvalidValue, MyStruct))

来抓族或细节.
仍然工作,只是参数,

struct MyStruct {}
//从上面,变成下面.
class InvalidValueExceptionWithMyStruct : InvalidValueException { MyStruct data; mixin ExceptionCtor;s }

当前,​​异常​​的信息不足.

我想用​​IFTI​​​:隐式函数模板实例化,来​​附加​​​数据,即要​​创建​​​新子类.它不能用​​普通​​​的构造函数.但可用​​opCall​​​.
此外,我还想确保​​​派生类​​​可在​​声明点​​​外命名,这样你可轻松​​抓异常​​​.这​​排除​​​了匿名类,但仍可用​​opCall​​.

深入代码

module exception2;

/+
它使用长格式模板编写,因为我想单独定义父
这样更容易.
+/
template Exception2(alias Type, T...) {
//每条添加数据都是更一般情况的特化
//这是通过父类不变,但切掉了一块来实现
//或作为所有`Exception2`的通用父级,并回退到`Exception`
static if(T.length)
alias Parent = Exception2!(Type, T[0 .. $-1]);
else
alias Parent = Exception;

class Exception2 : Parent {
//应该以不同的方式命名,或至少是`const`之类的
//但它保存在抛点传递的数据
T t;
//这是抛的主要入口点,注意它如何像`标库`中工厂模式一样,取参数并转发给新类
//在`Phobos`中用于构造,如,来自`map()`的`MapResult.`
//如果你直接使用`newException2`,必须指定所有要传递类型,但通过`opCall`,可隐式推导`R`.
//注意推导的返回值是传递过来的完整静态类型.

static opCall(R...)(R r, string file = __FILE__, size_t line = __LINE__) {
return new Exception2!(Type, T, R)(r, "", file, line); //串可包含任意
}

//你不能直接调用它!我甚至使它为`保护`
this(T t, string msg, string file = __FILE__, size_t line = __LINE__) {
this.t = t;
static if(is(Parent == Exception))
super(msg, file, line);
else
super(t[0 .. $-1], msg, file, line);
}

//这与旧的arsd.exception`基本相同
override void toString(scope void delegate(in char[]) sink) const {

import std.conv;

sink(typeid(this).name); //待办,同名长串.

sink("@");

sink(file);
sink(":");
sink(to!string(line));

sink("\n");

sink("玩笑");
//这部分是真实的:打印时,循环访问附加的数据并显示出来
foreach(idx, item; t) {
sink("\n");
sink(typeof((cast() this).t[idx]).stringof);
sink(" = ");
sink(to!string(item));
}

if(info) {
try {
sink("\n----------------");
foreach (t; info) {
sink("\n"); sink(t);
}
}
catch (Throwable) {
// 忽略更多错误.
}
}
}
}
}

这是灵活的类,它允许你定义​​catch(Exception2!X)​​​和​​throw Exception2!X(data)​​​,声明了返回​​为你构造​​​的​​更子类​​​的对象的​​opCall​​​.不是常见的静态​​opCall​​​,是我以前的​​旧模式​​​,并且它工作得很好.
我很满意.可方便地使用具​​​更多结构​​​的​​throw new Exception("stuff")​​.


举报

相关推荐

0 条评论