2013-10-07 1 views
5

Если вы пытаетесь вызвать метод на nil объекта в Ruby, возникает NoMethodError исключение с сообщением:Почему Object :: try работает, если он отправлен на нулевой объект?

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

Однако существует метод try в Rails, который просто возвращает nil, если он отправляется в nil объект:

require 'rubygems' 
require 'active_support/all' 

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

Так как же try работы внутри для того, чтобы предотвратить это исключение?

+0

«Если вы попытаетесь вызвать метод на объекте« nil »... возникает исключение» => Неверно. «Если вы попытаетесь вызвать метод ** undefined для' NilClass' ** на 'nil' ... exception возникает" => Исправить. – sawa

ответ

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), def ining метод, который возвращает 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.

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 объекта.

1

Он игнорирует аргумент и просто возвращает nil. Вот implementation:

class NilClass 
    def try(*args) 
    nil 
    end 
end 

Обратите внимание, что эта реализация всегда возвращает nil, даже если nil отвечает на метод:

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

Как и любой другой объект в Ruby, nil имеет класс (NilClass), который имеет методы. Например, nil? определено на NilClass, чтобы вернуть true, поэтому nil.nil? не возвращает NoMethodError.

Каждый класс в рубине может быть открыт (обновлен новыми методами). Rails открывает NilClass, чтобы добавить метод try и он вернется nil (который также почему try может быть прикован даже тогда, когда один шаг в цепи возвращается nil, потому что последующие nilтакже откликается на try).

Смежные вопросы