2015-12-18 9 views
21

Ruby 2.3 führt eine neue Methode unter Array und Hash mit der Bezeichnung ein. Die Beispiele, die ich in Blog-Posts über die neue Version gesehen habe, sind gekünstelt und verworren:Wie verwende ich `Array # dig` und` Hash # dig`, die in Ruby 2.3 eingeführt wurden?

# 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 

Ich bin nicht dreifach verschachtelte flache Arrays. Was ist ein realistisches Beispiel dafür, wie das sinnvoll wäre?

UPDATE

Es stellt sich heraus, diese Methoden lösen eine der am häufigsten gestellten Fragen Rubin. Die Fragen haben unter so etwas wie 20 Duplikate, die alle durch Verwendung gelöst werden:

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

Sie analysiert nur einige json ein sehr realistisches Beispiel ist ... – ndn

+0

@ ndn Die normale Verwendung 'user [: user] [: address] [: street1]' ist weniger Zeichen als 'user.dig (: user,: address,: street1)' und ergibt dasselbe Ergebnis. –

+7

@JesseSielaff Sie sind nicht das Gleiche. '[] [] []' wird mit einem Fehler fehlschlagen, wenn einer der Schlüssel nicht existiert. 'dig' wird nicht fehlschlagen, es wird' nil' zurückgeben. – meagar

Antwort

41

In unserem Fall NoMethodError s aufgrund nil Referenzen sind bei weitem die häufigsten Fehler, die wir in unseren Produktionsumgebungen zu sehen.

Der neue Hash#dig ermöglicht das Auslassen von nil Prüfungen beim Zugriff auf verschachtelte Elemente. Da Hashes am besten verwendet werden, wenn die Struktur der Daten unbekannt oder unbeständig ist, ist es sehr sinnvoll, eine offizielle Unterstützung dafür zu haben.

Nehmen wir Ihr Beispiel. Die folgende:

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

Ist nicht entspricht:

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

In dem Fall, wo user[:user] oder user[:user][:address]nil ist, wird dies in einem Laufzeitfehler.

Vielmehr ist es äquivalent zum folgenden, die das aktuellen Idiom ist:

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

Hinweis, wie es trivial ist, eine Liste von Symbolen zu übergeben, die an anderer Stelle in Hash#dig angelegt wurden, während es nicht sehr einfach ist, um das letztere Konstrukt aus einer solchen Liste neu zu erstellen. Hash#dig ermöglicht es Ihnen, leicht dynamischen Zugriff zu machen, ohne sich um nil Referenzen kümmern zu müssen.

Natürlich ist Hash#dig auch viel kürzer.


Ein wichtiger Punkt zur Kenntnis zu nehmen ist, dass Hash#dig selbst zurückgibt nil, wenn eine der Tasten entpuppt, die zu derselben Klasse von Fehlern einen Schritt auf der ganzen Linie führen können, so kann es sein, gute Idee, einen vernünftigen Standard zu liefern. (Diese Art, ein Objekt bereitzustellen, das immer auf die erwarteten Methoden reagiert, wird Null Object Pattern genannt.)

Wieder in Ihrem Beispiel, eine leere Zeichenfolge oder so etwas wie "N/A", je nachdem, was Sinn macht:

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

Ich wünschte, es gäbe einen 'Hash # dig!', Der das Äquivalent von # fetch's machen würde. – Dogweather

+0

@Dogweather: Sie können versuchen, eine Feature-Anfrage im [issue tracker] (https://bugs.ruby-lang.org/projects/ruby-trunk) einzureichen, und sehen, ob jemand sie abholt. :-) – Drenmi

+0

Alternative Idiome sind manchmal 'arr.fetch (: user, {}) .fetch (: address, {}) [: street1]' und für Rails, 'arr [: user] .try (: [] ,: Adresse) .try (: [],: street1) '. –

9

Ein Weg, mit dem Splat-Operator in Verbindung wäre von einem unbekannten Dokumentenmodell zu lesen.

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

Ah, das ist schlau. Ich hatte das in keinem Beispiel Posts gesehen. –

Verwandte Themen