很多时候,需要取这样的数据:
value = data[:row][:column][:field]
但是数据源并不是完整的,如果其中一层没有数据,需要返回空,如果一行行验证:
return unless data[:row]
return unless data[:row][:column]
value = data[:row][:column][:field]
有点繁琐,
也可以这样:
value = data[:row][:column][:field] rescue nil
不过我觉得是对 rescue 的滥用。
请问大家有什么好的方案没有?
恩,不成:
[1] pry(main)> data = Hash.new({})
=> {}
[2] pry(main)> data['a']['b']
=> nil
[3] pry(main)> data['a']['b']['c']
NoMethodError: undefined method `[]' for nil:NilClass
如果在 rails 环境下,贡献一个更丑的方式:
1.9.3p194 :001 > data = {a: 1, b:2}
=> {:a=>1, :b=>2}
1.9.3p194 :002 > data.try(:[], :a)
=> 1
1.9.3p194 :003 > data.try(:[], :c)
=> nil
恩,我想到了一个魔法:
class Hash
def loop_get *args
v = self
args.each do |arg|
return unless v[arg]
v = v[arg]
end
v
end
end
data = {}
data.loop_get :a, :b, :c # => nil
module NullableHash
class NullObject
def method_missing(*args)
self
end
def nil?
true
end
end
def [](sym)
super(sym) || NullObject.new
end
end
data.extend(NullableHash)
data[:sfsda][:bsdf][:csdf][:dsdf][:afsdfasdf].nil?
=> true
自己写一个
module Kernel
def try(&block)
block.call rescue nil
end
end
value = try { data[:row][:column][:field] }
@knwang 不到不得已的情况不赞成写 method_missing, rails 里面很少这样直接 method_missing 的,一般会在 method_missing 里面定义方法,不用每次都到 method_missing
如果要写一般的 Null Object 是要用 method_missing 的,因为需要对任何的 call 返回 self
http://en.wikipedia.org/wiki/Null_Object_pattern http://devblog.avdi.org/2011/05/30/null-objects-and-falsiness/
函数式解决方案:(其实和 6 楼的差不多,本质上也是 Null Object)
class Maybe < Struct.new(:o)
def chain m, *xs
v = o
xs.each do |x|
return if v.nil?
v = v.send m, x
end
v
end
end
value = Maybe[data].chain :[], :row, :column, :field
没污染,不仅适用于 []
,也适用于其他方法的 nil
链,data 为 nil
时也能工作
h = Hash.new{|h,k| Hash.new(&h.default_proc)} puts h['usa']['ny']['nyc'].inspect #=> {}