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

eli*_*lon 5 ruby ruby-on-rails activesupport

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

"undefined method ‘...’ for nil:NilClass"
Run Code Online (Sandbox Code Playgroud)

但是,try在Rails中有一个方法,nil如果它被发送到一个nil对象,它就会返回:

require 'rubygems'
require 'active_support/all'

nil.try(:nonexisting_method) # no NoMethodError exception anymore
Run Code Online (Sandbox Code Playgroud)

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

mde*_*tis 3

ActiveSupport 4.0.0定义了两种try方法:一种是用于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
Run Code Online (Sandbox Code Playgroud)

另一个是实例(对象):NilClassnil

class NilClass
  def try(*args)
    nil
  end
end
Run Code Online (Sandbox Code Playgroud)

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

class Test
  def returns_nil
    nil
  end
end
Run Code Online (Sandbox Code Playgroud)

因此,运行Test.new.try(:returns_nil)or被调用Test.new.not_existing_methodObject#try它检查公共方法是否存在(the 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)
Run Code Online (Sandbox Code Playgroud)

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