有没有更好的方法来编写这种类型的零检查?
我的代码中有几个地方我有嵌套对象,但不能保证它们总是被设置。
这可以给我一个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开始。
我认为更大的问题是这里违反了得墨忒耳的法律。 :-)你真的应该重新考虑同时接触这么多物体。