web-dev-qa-db-de.com

Wie verwende ich Array # Dig und Hash # Dig, das in Ruby 2.3 eingeführt wurde?

Ruby 2.3 führt eine neue Methode für Array und Hash mit dem Namen Dig ein. Die Beispiele, die ich in Blogeinträgen über die neue Version gesehen habe, sind erfunden und verschlungen:

# 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 verwende keine dreifach verschachtelten flachen Arrays. Was ist ein realistisches Beispiel dafür, wie dies nützlich wäre?

UPDATE

Es stellt sich heraus, dass diese Methoden eine der am häufigsten gestellten Ruby-Fragen lösen. Die folgenden Fragen haben ungefähr 20 Duplikate, die alle mit Dig gelöst werden:

Wie vermeide ich NoMethodError für fehlende Elemente in verschachtelten Hashes, ohne wiederholte Nullprüfungen?

Ruby Style: So prüfen Sie, ob ein verschachteltes Hash-Element vorhanden ist

31
user513951

In unserem Fall sind NoMethodErrors aufgrund von nil-Referenzen bei weitem die häufigsten Fehler, die wir in unseren Produktionsumgebungen sehen.

Mit dem neuen Hash#Dig können Sie beim Zugriff auf verschachtelte Elemente auf nil-Prüfungen verzichten. Da Hashes am besten verwendet werden, wenn die Struktur der Daten unbekannt oder unbeständig ist, ist es sinnvoll, diese Unterstützung offiziell zu erhalten. 

Nehmen wir ein Beispiel. Folgende:

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

Ist nicht äquivalent zu:

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

Wenn user[:user] oder user[:user][:address]nil ist, führt dies zu einem Laufzeitfehler.

Es ist vielmehr gleichwertig mit der aktuellen Redewendung:

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

Beachten Sie, wie einfach es ist, eine Liste von Symbolen, die an anderer Stelle erstellt wurde, in Hash#Dig zu übergeben, während das Erstellen des letzteren Konstrukts aus einer solchen Liste nicht einfach ist. Mit Hash#Dig können Sie auf einfache Weise einen dynamischen Zugriff durchführen, ohne sich um nil-Referenzen kümmern zu müssen.

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


Ein wichtiger Punkt, der zu beachten ist, ist, dass Hash#Dig selbst nil zurückgibt, wenn sich herausstellt, dass sich einer der Schlüssel als derselbe auswirkt, was zu einer gleichen Fehlerkategorie führen kann. Daher kann es sinnvoll sein, einen sinnvollen Standardwert anzugeben . (Diese Art der Bereitstellung eines Objekts, das immer auf die erwarteten Methoden reagiert, wird als Nullobjektmuster bezeichnet.)

In Ihrem Beispiel wiederum eine leere Zeichenfolge oder etwas wie "N/A", je nachdem, was sinnvoll ist:

user.Dig(:user, :address, :street1) || ""
54
Drenmi

Eine Möglichkeit wäre, den Splat-Operator aus 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
9
acsmith

Dies ist nützlich, wenn Sie sich durch tief verschachtelte Hashes/Arrays durcharbeiten möchten, die Sie beispielsweise von einem API-Aufruf erhalten würden.

In der Theorie wird eine Menge Code eingespart, der andernfalls auf jeder Ebene prüfen würde, ob eine andere Ebene vorhanden ist, ohne die Sie ständige Fehler riskieren. In der Praxis benötigen Sie möglicherweise noch eine Menge Code, da Dig in einigen Fällen immer noch Fehler erzeugt (z. B. wenn etwas in der Kette ein Objekt ohne Schlüssel ist).

Aus diesem Grund ist Ihre Frage wirklich gültig - Dig hat die erwartete Verwendung nicht erkannt. Dies wird zum Beispiel hier kommentiert: Warum niemand über Dig spricht.

Um Dig diese Fehler zu vermeiden, versuchen Sie das KeyDial gem, das ich geschrieben habe, um Dig zu wickeln, und erzwingen Sie, dass nil/default zurückgegeben wird, wenn ein Fehler auftritt.

0
Convincible