有没有更好的方法来编写这种类型的零检查?

时间:2012-02-06 10:54:11

标签: 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 个答案:

答案 0 :(得分:5)

我的试用版本:

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 }

<强>更新 让它变得更干净

答案 1 :(得分:4)

或使用andand。我更喜欢这个而不是符号,并且发现它更自然。

obj1.andand.obj2.andand.obj3.andand.obj4

答案 2 :(得分:3)

使用try。它不是来自Ruby库,但您可以轻松地将其添加到您的项目中。所以你将能够做到:

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

答案 3 :(得分:1)

除了lucapette提到的try approach之外,您还可以将该代码包装在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

答案 4 :(得分:1)

你肯定有一个更好的设计,链接检查零对象。被称为“可能monad”的模式特别擅长这项练习。首先,您必须将无类型的“Something或Nil”对象正确地包装到正确的“Maybe”对象中。那么,在你的情况下,你只需写:

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

这是一种功能性编程风格。如果您想尝试一下,可以从专为funkr gem设计的this can of usage开始。

答案 5 :(得分:0)

我认为更大的问题是这里违反了得墨忒耳的法律。 :-)你真的应该重新考虑同时接触这么多物体。

相关问题