“错误/异常”和“抛出/捕获”之间的区别?

时间:2014-06-25 14:58:43

标签: exception error-handling rebol rebol3

我对Rebol中的错误处理感到有点困惑。它有THROW和CATCH结构:

>> repeat x 10 [if x = 9 [throw "Nine!"]]
** Throw error: no catch for throw: make error! 2

>> catch [repeat x 10 [if x = 9 [throw "Nine!"]]]
== "Nine!"

但是这个抛出和捕获与传递给TRY上的/ EXCEPT细化的处理程序无关:

>> try/except [throw "Nine!"] [print "Exception handled!"]
** Throw error: no catch for throw: make error! 2

这对于Rebol的错误类型非常具体:

>> try/except [print 1 / 0] [print "Error handled!"]
Error handled!

如果你想要,你可以触发自己的错误,但不像其他语言那样使用THROW。抛出错误只会导致抱怨没有被抓住,就像任何其他价值类型一样:

>> try/except [throw make error! "Error string"] [print "Error handled!"]
** Throw error: no catch for throw: make error! 2

你必须让他们让评估者尝试执行类型错误的东西!导致它认为是“例外”

>> try/except [do make error! "Error string"] [print "Error handled!"]
Error handled!

(注意:cause-error 'Script 'invalid-type function!可{} use pre-made errors apparently - 有关详情,请参阅system/catalog/errors。)

退出/ EXCEPT细化将让您收到任何错误值。但是,这似乎无法区分错误是否被调用:

>> probe try [do make error! "Some error"]
make error! [
    code: 800
    type: 'User
    id: 'message
    arg1: "some error"
    arg2: none
    arg3: none
    near: none
    where: none
]
** User error: "Some error"

>> probe try [make error! "Some error"]
make error! [
    code: 800
    type: 'User
    id: 'message
    arg1: "Some error"
    arg2: none
    arg3: none
    near: none
    where: none
]
** User error: "Some error"

似乎CATCH在返回值和抛出值之间没有类似的区别。但是有一个工具可以通过“命名投掷”来解决这个问题:

>> code: [repeat x 10 [if x = 9 [throw/name "Nine!" 'number]]]

>> catch/name [do code] 'number
== "Nine!"

>> catch/name [do code] 'somethingelse
** Throw error: no catch for throw: make error! 2

现在问题是:

  • 这种分离是否有实际价值?如何决定是使用THROW和CATCH还是错误的DO并使用TRY / EXCEPT处理它?<​​/ p>

  • 这种区别是否在其他语言中有先例,并且/除了更好的名称/ ON-ERROR或其他什么?

  • 为什么会说"no catch for throw: make error! 2"而不是更具信息性的内容?什么是make error! 2

3 个答案:

答案 0 :(得分:5)

  

&#34;这种分离是否具有实际价值?如何决定是使用THROW和CATCH还是错误的DO并使用TRY / EXCEPT处理它?&#34;

正如其他答案中所指出的那样,THROW和CATCH构成了一个放松的构造(非本地出口),它本身就与控制流有关,并且不一定有任何关系有错误处理。 THROW和CATCH首先是影响控制流的直接方法,是其他自定义控制流构造的一个相当基础的构建块。

因此,THROW和CATCH当然也可以用于构建一个像许多当代主流语言中所见的异常处理类似错误系统,因为那些&#34;异常处理&#34;系统是非本地控制流程的一个实例。

另一方面,Rebol的error!是发出评估错误信号和传播的主要方法。

通常情况下,很容易做出决定:如果您想导致错误,请使用error!。如果您想影响控制流以可控地展开,请使用THROW / CATCH。

关于术语的另外两个评论:

  • 讨论Rebol错误has become more careful使用&#34; 导致错误&#34;作为短语而不是&#34;抛出错误&#34;,以避免混淆。
  • 以类似的方式,引用称为THROW / CATCH&#34; Rebol的异常处理&#34; (正如@HostileFork在一条评论中提到的那样)需要重新设计。
  

&#34;这种区别是否具有其他语言的先例&#34;

是的,评估错误和非本地退出之间的区别在其他语言中有先例,尤其是Lisp系列。一些快速参考:

  

&#34;为什么说&#34;没有抓住投掷:犯错误! 2&#34;而不是更具信息性的东西?什么是制造错误! ?2&#34;

这是一个错误。 (很好抓!)我说错误消息的核心(&#34;没有抓住投掷&#34;)已经提供了相当丰富的信息,但是make error! 2是一个错误(它应该是在这里显示抛出的值。)

  

&#34;会不会更好地命名/ ON-ERROR或其他什么?&#34;

重命名/EXCEPT是值得商榷的。因此,我说这是一个不适合SO Q&amp; A的讨论,最好留给其他论坛。

答案 1 :(得分:2)

我会说常规投掷不是用于错误处理,而是用于快捷方式或转到。它可以用作循环中断等。您也可以使用它来模仿继续

请参阅is-there-an-equivalent-to-continue

答案 2 :(得分:2)

我对Rebol中的错误处理不是很熟悉,但关于异常和抛出和捕获的问题是它们通常被认为是&#34;错误处理&#34;构造,这是一个相当狭隘的概念。相反,最好将try / catch视为流量控制机制。但是,退出循环只是退出一个直接的周围块,抛出异常所带来的好处是它可以跨越堆栈中的多个帧。因此,您可以更容易地将单个代码块作为逻辑单元隔离,如果它的任何部分失败,则可以将其视为逻辑单元的故障,无论异常发生在堆栈中有多远。

很抱歉,这可能没有直接回答你的问题,但我认为我可以解决你的第二点:它是否应该被称为ON-ERROR。我会说不,因为例外并不一定意味着错误;作为流量控制的一种手段,它只是一个更一般的指令,表明一个条件不应该允许在特定路径上进一步执行。