Есть ли лучший способ написать этот тип проверки на ноль? - PullRequest
1 голос
/ 06 февраля 2012

В моем коде есть несколько мест, где у меня есть вложенные объекты, но я не могу гарантировать, что они всегда будут установлены.

Это может дать мне неопределяемый метод ruby ​​для nil: NilClass

puts obj1.obj2.obj3.obj4.to_s

Эта проверка уродлива и повторяется:

if(obj1 && obj1.obj2 && obj1.obj2.obj3 && obj1.obj2.obj3.obj4)
  puts obj1.obj2.obj3.obj4.to_s
end

Есть ли краткий способ написать, если что-то ноль, просто молча провалиться?

Ответы [ 6 ]

5 голосов
/ 06 февраля 2012

Моя версия try:

class Object
  def try(*args, &block)
    if args.empty? and block_given?
      begin
        instance_eval &block
      rescue NameError => e
        puts e.message + ' ' + e.backtrace.first
      end
    elsif respond_to?(args.first)
      send(*args, &block)
    end
  end
end

Итак, вместо этого длинного выражения:

obj1.try(:obj2).try(:obj3).try(:obj4).to_s

вы можете сделать это:

obj1.try{ obj2.obj3.obj4.to_s }

ОБНОВЛЕНИЕ: Сделано немного чище

4 голосов
/ 06 февраля 2012

Или используйте и .Я предпочитаю это символам и нахожу это более естественным.

obj1.andand.obj2.andand.obj3.andand.obj4
3 голосов
/ 06 февраля 2012

Используйте , попробуйте . Это не из библиотеки Ruby, но вы можете легко добавить его в свой проект. Таким образом, вы сможете сделать:

obj1.try(:obj2).try(:obj3).try(:obj4)
1 голос
/ 06 февраля 2012

У вас наверняка может быть лучший дизайн, который объединяет проверки для нулевых объектов. Модель, известная как «Возможно, монада», особенно хороша в этом упражнении. Сначала вы должны правильно обернуть нетипизированные объекты "Something или Nil" в соответствующие объекты "Maybe". Тогда, в вашем случае, вы просто напишите:

puts obj1.bind(&:obj2).bind(&:obj3).bind(&:obj4)

Это функциональный стиль программирования. Если вы хотите попробовать, вы можете начать с funkr gem , который предназначен для этой банки использования .

1 голос
/ 06 февраля 2012

Помимо try подхода , упомянутого lucapette, вы также можете заключить этот код в begin; rescue; end и просто спасти NameError:

begin
    if(obj1 && obj1.obj2 && obj1.obj2.obj3 && obj1.obj2.obj3.obj4)
        puts obj1.obj2.obj3.obj4.to_s
    end
rescue NameError
end

Вы можете увидеть разницу по этому коду:

#!/usr/bin/ruby

p :not_defined

begin
    if(obj1 && obj1.obj2 && obj1.obj2.obj3 && obj1.obj2.obj3.obj4)
        puts obj1.obj2.obj3.obj4.to_s
    end
rescue NameError
    p :ouch
end

p :defined_all_the_way

class Yup
    def method_missing(m, *a, &b)
        self
    end

    def to_s
        :yup
    end
end
obj1 = Yup.new

begin
    if(obj1 && obj1.obj2 && obj1.obj2.obj3 && obj1.obj2.obj3.obj4)
        puts obj1.obj2.obj3.obj4.to_s
    end
rescue NameError
    p :ouch
end

__END__
Results in:
:not_defined
:ouch
:defined_all_the_way
yup
0 голосов
/ 06 февраля 2012

Я думаю, что большая проблема - это нарушение закона Деметры здесь.:-) Вы действительно должны пересмотреть вопрос о том, чтобы охватить столько объектов одновременно.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...