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

我的代码中有几个地方我有嵌套对象,但不能保证它们总是被设置。

这可以给我一个nil的ruby未定义方法: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 

是否有一种简洁的写作方式,如果有什么是零只是默默地失败?

我试试的版本:

 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 } 

更新:让它更清洁一点

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

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

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

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

除了lucapette提到的try方法之外,你还可以将该代码包装在begin; rescue; end begin; rescue; end 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 

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

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

这是一种函数式编程风格。 如果你想尝试一下,你可以从为这种用途而设计的funkr gem开始。

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