Exception D语言中的惯用错误处理

Exception D语言中的惯用错误处理,exception,error-handling,scope,d,Exception,Error Handling,Scope,D,我试图找到关于处理错误的标准化和公认的惯用D方式的资源,但我找不到任何。如果你正在阅读官方文件,那么你会发现以下非常重要的陈述: 错误不是程序正常流程的一部分。错误是异常的、不寻常的和意外的 因为错误是不寻常的,所以执行错误处理代码并不是性能关键 程序逻辑的正常流程对性能至关重要 我把它们称为重要的,因为对这种,嗯,例外情况使用例外的推理是导致本文得出结论的原因,错误毕竟是特殊情况,例外是要走的路,不管代价是什么。同样来自同一篇文章: 因为错误是不寻常的,所以执行错误处理代码并不是性能关键。

我试图找到关于处理错误的标准化和公认的惯用D方式的资源,但我找不到任何。如果你正在阅读官方文件,那么你会发现以下非常重要的陈述:

  • 错误不是程序正常流程的一部分。错误是异常的、不寻常的和意外的
  • 因为错误是不寻常的,所以执行错误处理代码并不是性能关键
  • 程序逻辑的正常流程对性能至关重要
我把它们称为重要的,因为对这种,嗯,例外情况使用例外的推理是导致本文得出结论的原因,错误毕竟是特殊情况,例外是要走的路,不管代价是什么。同样来自同一篇文章:

因为错误是不寻常的,所以执行错误处理代码并不是性能关键。异常处理堆栈展开是一个相对缓慢的过程

在某些特殊情况下,异常可能不会被显式处理,但它们的存在无论如何都会影响事物的状态,因此应该使用

我的主要问题是,上述解决方案及其文档中的示例确实是例外情况,当我们遇到例如内存相关的问题时,它们非常有用,但我们不希望我们的程序失败,我们希望保持完整性并在可能的情况下从这些场景中恢复,但是其他的情况呢

众所周知,错误不仅用于异常情况和意外情况,而且是呼叫者和被呼叫者之间的通信方式。例如,可以在消毒剂中使用错误。假设我们要为关联数组实现模式验证。类型系统本身无法定义键和值的约束,因此我们创建了一个函数来在运行时检查这些对象。那么,如果模式失败,会发生什么呢?因为我们对它是如何失败的感兴趣,所以它中发生的错误(即发现的无效数据)也应该包含错误的信息,因此调用方知道如何处理它。根据第一篇文章的作者所说,使用异常是一种昂贵的抽象。根据同一篇文章中同一位作者的观点,使用C风格的函数约定(返回值都用于错误状态)是错误的


那么,处理D中不是异常的错误的正确和惯用的方法是什么呢?

好的,TLDR版本是使用异常是处理D中错误条件的惯用方法,但当然,细节要比这复杂一些

问题的一部分是什么构成了错误。“错误”一词用于很多事情,因此,谈论错误可能会让人非常困惑。有些类错误是编程错误(因此是程序错误的结果),其他类错误不是编程错误,但灾难性严重,程序无法继续,其他类错误依赖于用户输入等内容,通常可以从中恢复

对于编程错误和灾难性错误,D有
Error
类,该类派生自
Throwable
Error
的两个常用子类是
AssertError
RangeError
-
AssertError
是断言失败的结果,而
RangeError
是尝试使用超出范围的索引对数组进行索引时得到的结果。这两个都是程序错误;它们是程序中错误的结果,从中恢复是没有意义的,因为根据定义,此时程序处于无效状态。一个不是bug但通常灾难性足以导致程序终止的错误示例是
MemoryError
,当
new
无法分配内存时抛出该错误

当抛出
错误
时,不能保证任何清理代码都会运行(例如,可以跳过析构函数和
scope
语句,因为假设您的代码处于无效状态,清理代码实际上可能会使事情变得更糟)。程序只需展开堆栈,打印出
错误的消息和堆栈跟踪,然后终止程序。因此,试图捕捉一个
错误
并让程序继续运行几乎总是一个糟糕的想法,因为程序处于未知和无效状态。如果某个东西被认为是一个
错误
,那么它就是那种错误情况被认为是不可恢复的,程序不应该试图从中恢复

在大多数情况下,您可能不会对
Error
s执行任何显式操作。当不使用-release编译时,您将在代码中放置断言以捕获bug,但您可能不会显式抛出任何
错误。它们主要是D的运行时或您正在运行的代码中的断言捕获程序中的错误的结果

另一个从
Throwable
派生的类是
Exception
。它用于以下情况:问题不是程序中的错误,而是由于用户输入或环境造成的问题(例如,用户提供的XML无效,或者程序试图打开的文件不存在)。异常为函数提供了一种报告其输入无效或由于无法控制的问题而无法完成任务的方法。然后,程序可以选择捕获该
异常
并尝试从中恢复,也可以让它冒泡到顶部并杀死程序(尽管通常,捕获它们并打印出比带有堆栈跟踪的消息更用户友好的内容更用户友好)。与
错误
s不同,
异常
s会导致所有CLE
int isDir(string filename, ref bool result);
if(file.isDir)
{
    ...
}
bool result;
immutable error = file.isDir(result);
if(error != 0)
{
    ...
}
else if(result)
{
    ...
}