为什么会抛出一个非符号?

时间:2016-02-17 07:17:38

标签: ruby

Ruby的throw语句接受任何Object,这意味着以下任何一项都是合法的。

throw BasicObject
throw 123456.78
throw "wow"
throw :doge

但是,根据我的理解,我选择抛出Symbol有两个原因。

  1. 必须catch投掷完全相同的Object。这意味着执行catch "wow"会产生UncaughtThrowError。使用Symbol时,这不是问题。
  2. Object后无法引用被引发的catch。要指定一个返回值,可以将其作为第二个参数输入:throw :doge, "wow"这会破坏我认为抛出自定义Object的全部意义..
  3. 此外,令人困惑的是throw的(第一个)参数在Symbols之前曾被限制为ruby 1.9。这是否意味着有人必须throw非符号,并且ruby必须更改其实现以允许此类用例?或者它是别的......比如节省类型检查的执行时间。

    此时,我唯一可以想象的是Symbol s与Fixnum s分开,但这是改变的原因吗?请赐教。

1 个答案:

答案 0 :(得分:5)

假设您正在使用一些您不关心其内部的库。如果该库使用throw方法与某个符号(或任何其他常见对象)意外碰巧与您throw相同的符号(或对象) - 在您自己的代码中?它会导致不必要的交互。另一方面,如果您创建自定义对象并将其抛出,则无需关心此类问题。特别是如果您仅将其定义为局部变量,那么它将是安全的。如果将其定义为常量,那么它将是相对安全的(危险是其他库在同一名称空间中意外使用相同的常量名称)。

带有块参数的

catch创建Object的实例,并将其指定为块变量,这样可以确保安全。

当我使用throw时,我通常无法使用块变量形式,因为大多数时候,我throwcatch使用不同的方法。因此,我创建了Object的实例,并将其指定为私有常量,这使其相对安全。

class SomeClass
  Foo = Object.new
  private_constant :Foo

  def some_method
    ...
    catch(Foo){... another_method ...}
    ...
  end
  def another_method
    ...
    throw(Foo)
    ...
  end
end