我的代码中有几个地方有嵌套对象,但不能保证它们总是会被设置。
这可以给我一个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
是否有一种简洁的写作方式,如果有什么是零只是默默地失败?
答案 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)
我认为更大的问题是这里违反了得墨忒耳的法律。 :-)你真的应该重新考虑同时接触这么多物体。