Soru Ruby 2.3'te sunulan "Array # dig" ve "Hash # dig" ı nasıl kullanırım?


Ruby 2.3 yeni bir yöntemi tanıtıyor Array ve Hash denilen dig. Yeni sürümle ilgili blog gönderilerinde gördüğüm örnekler uyuşuyor ve kıvrılıyor:

# 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

Üçlü yuvalanmış düz diziler kullanmıyorum. Bunun nasıl faydalı olacağına dair gerçekçi bir örnek nedir?

GÜNCELLEŞTİRME

Bu yöntemler, en sık sorulan Ruby sorularından birini çözer. Aşağıdaki sorular, hepsi de kullanılarak çözülen 20 kopya gibi bir şeye sahiptir. dig:

Yuvalanmış hashlardaki eksik elemanlar için NoMethodError'dan nasıl kaçınılamaz, tekrar tekrar kontrol edilmez mi?

Ruby Style: Yuvalanmış hash elemanının var olup olmadığını kontrol etme


25
2017-12-18 00:18


Menşei


Sadece biraz json ayrıştırdın çok gerçekçi bir örnek ... - ndn
@ndn Normal kullanım user[:user][:address][:street1] daha az karakter user.dig(:user, :address, :street1) ve aynı sonucu verir. - Jesse Sielaff
@JesseSielaff Aynı şey değiller. [][][] Anahtarlardan herhangi biri yoksa bir hatayla başarısız olur. dig başarısız olmaz, geri dönecek nil. - meagar♦
Öncelikle, indekslemeyi kullanırsanız ve yol boyunca bir şey eksik kalırsa, nil sınıfı için yöntem hatası almazsınız. İkinci olarak, dinamik aramalar yapmak daha kolaydır. dig yöntem. - ndn


Cevaplar:


Bizim durumumuzda NoMethodErrornedeniyle nil Referanslar, üretim ortamlarımızda gördüğümüz en yaygın hatalardır.

Yeni Hash#dig atlamana izin verir nil iç içe geçmiş öğelere erişirken denetler. Verilerin yapısı bilinmediğinde ya da uçucu olduğu için karmaların en iyi şekilde kullanıldığından, bunun için resmi desteğe sahip olmak çok mantıklıdır.

Örneğini alalım. Aşağıdaki:

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

değil eşittir:

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

Durumda user[:user] veya user[:user][:address] olduğu nilBu çalışma zamanı hatasıyla sonuçlanır.

Daha ziyade, şu anki deyim olan aşağıdakilere eşdeğerdir:

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

Başka bir yerde yaratılmış olan sembollerin listesini aktarmanın önemsiz olduğunu unutmayın. Hash#digBununla birlikte, ikinci yapının böyle bir listeden yeniden oluşturulması çok kolay değildir. Hash#dig endişelenmenize gerek kalmadan kolayca dinamik erişim yapmanızı sağlar nil Referanslar.

Açıkça Hash#dig ayrıca çok daha kısa.


Dikkat çekmek için önemli bir nokta Hash#dig kendisi döndürür nil Eğer herhangi bir tuş ortaya çıkarsa, bu da aynı hata sınıfına bir satır aşabilir, bu yüzden mantıklı bir varsayılan sağlamak için iyi bir fikir olabilir. (Her zaman beklenen yöntemlere cevap veren bir nesne sağlamanın yolu denir. Boş Nesne Kalıbı.)

Yine, örneğinizde, neyin mantıklı olduğuna bağlı olarak boş bir dize veya "N / A" gibi bir şey:

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

43
2017-12-18 04:12



Keşke orada olsaydı Hash#dig! Birden fazla # getirme eşdeğerini yapar. - Dogweather
@Dogweather: Bir özellik isteği göndermeyi deneyebilirsiniz. sorun izleyicive birilerinin onu alıp almadığını görün. :-) - Drenmi
Bazen görülen alternatif deyimler arr.fetch(:user, {}).fetch(:address, {})[:street1] ve Rails için arr[:user].try(:[], :address).try(:[], :street1). - matthew.tuck
@Drenmi, eski bir [: a] [: b] sözdizimini kazıda kullanmak için hala tercih edilen olası durumlar var, zira bir anahtar aşağı zincirine erişmem gerekiyor mu? - Martin Verdejo
@JesseSielaff: Kısa bir açıklama ve ilgili bir bağlantı ekledim. - Drenmi


Bir yol, bilinmeyen bir belge modelinden okuyan uyarıcı işleç ile bağlantılı olacaktır.

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
2017-12-18 00:26



Ah, bu zekice. Bunu herhangi bir örnek yazıda görmemiştim. - Jesse Sielaff