我不知道在​​单元测试块​​​和​​合同​​​中抓​​错误​​​行为不一样.
一个反馈是​​​非主线程​​​.尽管都同意不应​​抓错误​​​,但​​主线程​​​会这样并打印文章中显示的​​有用输出​​​.
如果允许​​​主线程​​​这样做,也应在​​非主线程​​​做同样多(或更少)的事情.否则,无法跟踪​​线程​​.

如果偏执并想尽量少做,至少应​​复制​​​串字面到​​stderr​​​.类似"线程因​​错误​​​退出".然后退出​​(1)​​​.
不抓错误的规则,是打印​​​诊断​​​信息.但此后,不应继续运行​​程序​​.

如果​​线程​​​未抓错误并结束​​程序​​​,这是​​运行时​​​缺陷.
我过去认为不应​​​抛错误​​​,而是​​记录错误​​​(包括调用栈),然后甚至​​不展开​​​栈的退出.但是代码至少期望​​抛错误栈​​​,这样​​期望​​​抓它的代码会​​中断​​.

除非用​​std.concurrency​​​,且​​主线程​​​查找并接收​​LinkTerminated​​​消息(用​​spawnLinked​​启动线程).

void myThread() {
try {

} catch (Exception exc) {
// ...

} catch (Error exc) {
// 报告错误
exit(1); // 退出或其他
}
}

一般,不必继承​​Error​​​.​​用户代码​​​中抛​​错误​​​的最常见的方法是使用​​assert​​​,它(有​​默认​​​编译器标志)在失败时抛​​AssertError​​​.​​函数合同​​​和​​构/类不变量​​工作方式相同

可提供必须抛​​错误​​​而不能抛适当​​异常​​代码吗?

这完全是设计​​API​​​的问题.如果​​调用者​​​在调用函数前​​检查​​​某些条件,则可在​​条件不成立​​​时抛​​Error​​​(或更有可能使用​​assert​​​或​​in​​​合同来检查它).如果是​​被调用者​​​检查,则应抛​​Exception​​​(或使用​​enforce​​).

​Error​​​的要点是​​代码​​​可假定它不会​​发生​​​,如果发生了,则​​代码无效​​​.
反映在编译器,则在抛​​​错误​​​时,会省略​​清理代码​​​(可假设它​​永远不会​​​).使用​​Error​​​目的是最后​​检查​​​程序​​正确性​​​(因为在到达​​该点​​​前未能​​验证输入​​).

如果抛​​错误​​​,​​vibe​​​应退出.在​​vibe​​​代码中总是​​困扰​​​我的是,​​越界​​​数组错误.我用抛​​异常​​​包装器替换了一些数组,因为有时我不想使​​整个服务器​​​崩溃,也不想连续​​验证​​数组索引.

只要未抓到​​可抛或错误​​​,就应该没问题.简单不标记事物为​​nothrow​​​,并不表明它们不会按​​nothrow​​​推导.​​auto​​​和​​模板函数​​​都是​​推导​​​出来.
可能​​​很少​​​会咬到你.但也表明,如果它真的咬人,那真的​​很难追踪​​​.
正如​​​Paul​​​所说,这根据你的​​API​​​.如果假定已清理​​函数输入​​​,如果超出规范,则可​​正确​​抛错误.

很好示例是​​区间​​​函数.你经常会在​​popFront​​​方法的开头,看到​​assert(!empty);​​​语句.这是普遍接受的,因为如果不检查​​empty​​​,则不应调用​​popFront​​.

​不应​​​重试错误,且不应​​抛错误​​​.
​​​OutOfMemoryError​​​不应是​​错误​​​,而是​​异常​​​.因为无法在​​分配​​​前检查​​分配​​​是否成功,并且,有些方法可在​​不关闭​​​进程就处理​​内存不足​​​问题.
可​​​抓并重试​​​异常.​​预测失败​​​,然后​​抛异常​​​是可行的.
​​​100%​​​安全,在具有​​最小共享内存​​​的​​单独进程​​中运行它.

你不​​假定​​​它,你​​保证​​​它.你要向​​编译器​​​保证代码不会​​抛错误​​​.
但是你并不完美,所以可能犯了​​​错误​​​,并触发了​​错误(Error)​​​.编译器​​展开栈​​​并回到​​主函数​​​,​​打印​​​错误并退出,因此可修复你犯的​​错误​​​.
类似​​​段错误​​​.不应该读取​​不拥有​​​的内存(是的,我知道可用​​段错误​​​来触发​​加载内存​​​,我不是在谈论那种段错误).则当​​意外段错误​​​时怎么做?​​崩溃​​​程序,然后​​退出​​​.这里,默认,​​语言​​​会为你提供有关​​位置​​​提示,还可在​​所需位置​​​抓错误并​​检查​​​更多等,来取​​更多信息​​.

但是,我确实向​​Walter​​​询问了这个问题,他说要像​​goto​​​一样对待​​抛/抓​​​错误.
​​​错误​​​的意义在于可​​删除​​​它们来​​提高效率​​​.即,就像​​断定​​​或​​检查边界​​​一样,它们不应成为​​正常​​​程序的一部分.而​​异常​​​是程序的​​一部分​​​,并提供了不同机制来​​处理错误​​.

但是可关闭​​断定​​​并使代码运行得更快.我个人从不在某些程序(​​网络​​​服务器)上关闭它们,因为​​代价​​​不够明显.但如果这些是​​异常​​​,就不能​​关闭​​它们.

考虑​​foreach​​​循环中​​区间​​的正常流:

// foreach(elem; range)
for(auto r = range; !r.empty; r.popFront) {
auto elem = r.front;
}

如果​​popFront​​​和​​front​​​两者都调用​​empty​​​,则每个循环调用3次​​empty​​​,​​第2次和第3次​​​调用值相同.有了断定可在​​不崩溃​​​程序下就​​诊断​​​无效程序,而且还可在​​需要​​​时提供​​完整​​性能.

​d​​​的标准库的​​红黑树​​​有个遍历整个​​RBT​​​并在每个方法调用​​之前和之后​​​,验证红黑树​​invariant​​​属性的方法.这不是你想要的​​高性能​​​代码,因为它完全破坏了​​复杂性​​​保证.但是,如果你正在​​修改​​​它,可帮助诊断​​RBT​​​的问题.这些​​检查​​​是为了帮助​​开发人员​​​证明​​代码​​​是正确的,而不必​​不断​​​地证明,对​​正常使用​​是正确的.

​这里​​​​这里​​​​这里​