可能性のある複製:
Ruby:IFステートメントのNils
ネストされたparamsハッシュでnilのメソッドを呼び出すことを避けるためのクリーンな方法はありますか?
このようなハッシュにアクセスしようとするとしましょう:
my_hash['key1']['key2']['key3']
Key1、key2、key3がハッシュに存在する場合、これは素晴らしいことですが、たとえばkey1が存在しない場合はどうでしょうか?
次に、NoMethodError: undefined method [] for nil:NilClass
。そして誰もそれが好きではありません。
これまでのところ、私はこれを次のような条件付きで処理しています:
if my_hash['key1'] && my_hash['key1']['key2']
...
これは適切ですか、そうする他の最もルービィな方法はありますか?
これには多くのアプローチがあります。
Ruby 2.3以上を使用する場合、 Dig を使用できます
my_hash.Dig('key1', 'key2', 'key3')
たくさんの人が平野Rubyに固執し、&&
ガードテスト。
Stdlib Hash#fetch も使用できます:
my_hash.fetch('key1', {}).fetch('key2', {}).fetch('key3', nil)
ActiveSupportの #try メソッドのチェーンが好きです。
my_hash.try(:[], 'key1').try(:[], 'key2').try(:[], 'key3')
その他は andand を使用します
myhash['key1'].andand['key2'].andand['key3']
一部の人々は、 egocentric nils が良い考えだと考えています(ただし、誰かがあなたを追い詰めて、あなたがこれを見つけた場合はあなたを拷問するかもしれません)。
class NilClass
def method_missing(*args); nil; end
end
my_hash['key1']['key2']['key3']
Enumerable#reduce (またはエイリアス注入)を使用できます。
['key1','key2','key3'].reduce(my_hash) {|m,k| m && m[k] }
または、ネストされたルックアップメソッドを使用して、ハッシュまたはターゲットハッシュオブジェクトを拡張することもできます。
module NestedHashLookup
def nest *keys
keys.reduce(self) {|m,k| m && m[k] }
end
end
my_hash.extend(NestedHashLookup)
my_hash.nest 'key1', 'key2', 'key3'
ああ、どうすれば 多分 モナドを忘れることができるでしょうか?
Maybe.new(my_hash)['key1']['key2']['key3']
Object#andand を使用することもできます。
my_hash['key1'].andand['key2'].andand['key3']
条件my_hash['key1'] && my_hash['key1']['key2']
感じない [〜#〜] dry [〜#〜] 。
代替案:
1) autovivification magic。その投稿から:
def autovivifying_hash
Hash.new {|ht,k| ht[k] = autovivifying_hash}
end
次に、あなたの例で:
my_hash = autovivifying_hash
my_hash['key1']['key2']['key3']
Hash.fetchアプローチに似ていますが、両方ともデフォルト値として新しいハッシュで動作しますが、これにより詳細が作成時に移動します。確かに、これはちょっとした不正行為です。「nil」だけで空のハッシュが返されることはなく、その場で作成されます。ユースケースにもよりますが、これは無駄です。
2)ルックアップメカニズムを使用してデータ構造を抽象化し、バックグラウンドで見つからないケースを処理します。単純な例:
def lookup(model, key, *rest)
v = model[key]
if rest.empty?
v
else
v && lookup(v, *rest)
end
end
#####
lookup(my_hash, 'key1', 'key2', 'key3')
=> nil or value
3)モナドを感じたら、これを見てみることができます 多分