为什么Object ::尝试工作,如果它被发送到一个零对象?

时间:2013-10-07 12:15:09

标签: ruby-on-rails ruby activesupport

如果您尝试在Ruby中的nil对象上调用方法,则会出现NoMethodError异常,并显示以下消息:

"undefined method ‘...’ for nil:NilClass"

但是,Rails中有一个try方法,如果它被发送到nil对象,则只返回nil

require 'rubygems'
require 'active_support/all'

nil.try(:nonexisting_method) # no NoMethodError exception anymore

那么try如何在内部工作以防止该异常呢?

4 个答案:

答案 0 :(得分:3)

与Ruby中的每个其他对象一样,nil有一个类(NilClass),它有方法。例如,nil?上定义了NilClass以返回true,这就是nil.nil?不返回NoMethodError的原因。

ruby​​中的每个类都可以打开(使用新方法更新)。 Rails会打开NilClass以添加try方法并让它返回nil(即使链中的一个步骤返回try,也可以链接nil的原因},因为后续nil 响应try)。

答案 1 :(得分:2)

来自Rails(3.2)documentation

  # Object#try:
  def try(*a, &b)
    if a.empty? && block_given?
      yield self
    else
      __send__(*a, &b)
    end
  end

  # NilClass#try (http://apidock.com/rails/NilClass/try):
  def try(*args)
    nil
  end

方法try只是为nil对象单独实现,因此它始终返回nil,即使您尝试调用的方法是为nil对象实现的。

答案 2 :(得分:2)

ActiveSupport 4.0.0定义了两种try方法:one用于Object个实例:

class Object
  def try(*a, &b)
    if a.empty? && block_given?
      yield self
    else
      public_send(*a, &b) if respond_to?(a.first)
    end
  end
end

other适用于NilClass个实例(nil个对象):

class NilClass
  def try(*args)
    nil
  end
end

现在,假设我们有一个Object实例(不包括nil,实际上继承自Object,就像Ruby中的其他所有实例一样),定义一个返回nil的方法:

class Test
  def returns_nil
    nil
  end
end

因此,运行Test.new.try(:returns_nil)Test.new.not_existing_method,将调用Object#try,这将检查是否存在公共方法(respond_to?);如果是这样,它将调用方法(public_send),否则它将返回nil(没有其他行)。

如果我们在这些返回的try方法上调用另一个nil

Test.new.try(:returns_nil).try(:any_other_method)
Test.new.try(:not_existing_method).try(:any_other_method)

我们会调用NilClass#try,即nil#try,它会忽略所有内容并返回nil。因此,任何其他try将在nil个实例上调用并返回nil

答案 3 :(得分:1)

它忽略了参数,只返回nil。这是implementation

class NilClass
  def try(*args)
    nil
  end
end

请注意,即使nil响应方法,此实现也始终返回nil

nil.try(:to_i) # => nil, rather than 0