如果将 Object::try 发送到 nil 对象,为什么它会起作用?

问题描述 投票:0回答:4

如果您尝试在 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
如何在内部工作以防止这种异常?

ruby-on-rails ruby activesupport
4个回答
3
投票

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
投票

与 Ruby 中的所有其他对象一样,

nil
有一个类 (
NilClass
),该类具有方法。例如,在
nil?
上定义
NilClass
返回 true,这就是为什么
nil.nil?
不返回
NoMethodError

Ruby 中的每个类都可以开放(用新方法更新)。 Rails 打开

NilClass
添加
try
方法并让它返回
nil
(这也是为什么即使链中的一个步骤返回
try
也可以链接
nil
,因为后续的
nil
回复
try
)。


2
投票

来自 Rails (3.2) 文档

  # 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
对象实现的。


1
投票

它忽略参数并仅返回

nil
。这是实现

class NilClass
  def try(*args)
    nil
  end
end

请注意,此实现始终返回

nil
,即使
nil
响应该方法:

nil.try(:to_i) # => nil, rather than 0
© www.soinside.com 2019 - 2024. All rights reserved.