2015-12-18 5 views
21

ArrayHashについては、という新しいメソッドが導入されています。私は新しいリリースに関するブログ記事で見てきた例は不自然と複雑です:Ruby 2.3で導入された `Array#dig`と` Hash#dig`はどうやって使うのですか?

# Hash#dig 
user = { 
    user: { 
    address: { 
     street1: '123 Main street' 
    } 
    } 
} 

user.dig(:user, :address, :street1) # => '123 Main street' 

# Array#dig 
results = [[[1, 2, 3]]] 
results.dig(0, 0, 0) # => 1 

私はトリプルネストされたフラットな配列を使用していませんよ。これがどのように役立つのか現実的な例は何ですか?

UPDATE

それは結局のところ、これらの方法は、最も一般的に尋ねたRubyの質問のいずれかを解きます。以下の質問はを使用することによって解決されているすべてのそれらの20個の重複、のようなものを持っている:

How to avoid NoMethodError for missing elements in nested hashes, without repeated nil checks?

Ruby Style: How to check whether a nested hash element exists

+1

あなただけのいくつかのJSONを解析され、非常に現実的な例... – ndn

+0

です@ ndn通常の 'user [:user] [:address] [:street1]'は 'user.dig(:user、:address、:street1)'より少ない文字で、同じ結果を与えます。 –

+7

@JesseSielaff彼らは同じではありません。キーのいずれかが存在しない場合、 '[] [] []'はエラーで失敗します。 'dig'は失敗しません。' nil'を返します。 – meagar

答えて

41

nil参照によるNoMethodError sが我々が本番環境でご覧はるかに最も一般的なエラーです。

新しいHash#digを使用すると、ネストされた要素にアクセスするときにチェックを省略することができます(nil)。ハッシュは、データの構造が不明であるか、または揮発性である場合に最もよく使用されるため、これに対する正式なサポートは大変意味があります。

例を見てみましょう。次

user.dig(:user, :address, :street1) 

と等価ではないです:user[:user]またはuser[:user][:address]nilある場合には

user[:user][:address][:street1] 

、これは実行時エラーになります。

むしろ、それは現在のイディオムである、以下に相当します。

user[:user] && user[:user][:address] && user[:user][:address][:street1] 

注それは非常に簡単ではないのに対し、Hash#digに別の場所で作成されたシンボルのリストを渡すことは簡単ですかそのようなリストから後者の構成を再作成する。 Hash#digは、nilの参照を心配することなく、簡単に動的アクセスを行うことができます。

明らかにHash#digもかなり短くなっています。ノートを取るために


一つの重要な点は、キーのいずれかが一歩行下のエラーの同じクラスにつながる可能性が、あることが判明するので、それができるならばHash#dig自体がnilを返すということです賢明なデフォルトを提供することをお勧めします。 (期待される方法に常に応答するオブジェクトを提供するこの方法は、Null Object Patternと呼ばれます。)

ここでも、あなたの例では、理にかなっているものに応じて、「N/A」のような空の文字列か何か、:

user.dig(:user, :address, :street1) || "" 
+0

複数の#fetchに相当する 'Hash#dig! 'があったらいいのに。 – Dogweather

+0

@Dogweather:[issue tracker](https://bugs.ruby-lang.org/projects/ruby-trunk)に機能リクエストを送信して、誰かがそれを受け取ったかどうかを確認することができます。 :-) – Drenmi

+0

Railsの場合、arr [:user] .try(:[])は、arr.fetch(:user、{})フェッチ(:アドレス、{})[:street1] 、:アドレス).try(:[]、:street1) '。 –

9

一つの方法は、いくつかの未知の文書モデルからの読み取りスプラット演算子と一緒になります。我々の場合には

some_json = JSON.parse('{"people": {"me": 6, ... } ...}') 
# => "{"people" => {"me" => 6, ... }, ... } 
a_bunch_of_args = response.data[:query] 
# => ["people", "me"] 
some_json.dig(*a_bunch_of_args) 
# => 6 
+2

ああ、それは賢いです。私はどの例の記事でもそれを見ていなかった。 –

関連する問題