Вопрос по ruby, conditional, hash – Ruby - доступ к многомерному хешу и отказ от доступа к nil-объекту [duplicate]

81

Possible Duplicate:
Ruby: Nils in an IF statement
Is there a clean way to avoid calling a method on nil in a nested params hash?

Допустим, я пытаюсь получить доступ к хешу, например так:

<code>my_hash['key1']['key2']['key3']
</code>

Это хорошо, если key1, key2 и key3 существуют в хешах, но что если, например, key1 не существует?

Тогда я бы получилNoMethodError: undefined method [] for nil:NilClass, И никому это не нравится.

До сих пор я имею дело с этим, делая условно, как:

if my_hash['key1'] && my_hash['key1']['key2'] ...

Это уместно, есть ли другой Ruby способ сделать это?

Извините сообщество. Я пытался найти это и не мог найти это. Закройте, если необходимо. Nobita
В принятом ответе упоминаются все возможные методы, кроме правильного для Ruby 2.3+:ruby-doc.org/core-2.3.1/Hash.html#method-i-dig Eric Duminil

Ваш Ответ

3   ответа
5

my_hash['key1'] && my_hash['key1']['key2'] не чувствуюDRY.

Альтернативы:

1) autovivification магия. Из этого поста:

def autovivifying_hash
   Hash.new {|ht,k| ht[k] = autovivifying_hash}
end

Тогда, с вашим примером:

my_hash = autovivifying_hash     
my_hash['key1']['key2']['key3']

Он аналогичен подходу Hash.fetch в том, что оба работают с новыми хэшами в качестве значений по умолчанию, но это перемещает детали во время создания. По общему признанию, это - немного обмана: это никогда не возвратит 'ноль' просто пустой хеш, который создается на лету. В зависимости от вашего варианта использования это может быть расточительным.

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) Если вы чувствуете себя монадическим, вы можете взглянуть на это,Может быть

158

Если вы используете Ruby 2.3 или выше, вы можете использоватькопать землю

my_hash.dig('key1', 'key2', 'key3')

Множество людей придерживаются простого рубина и связывают&& охранные тесты.

Вы могли бы использовать stdlibHash # выборки тоже:

my_hash.fetch('key1', {}).fetch('key2', {}).fetch('key3', nil)

Некоторым нравится цепочка ActiveSupport#пытаться метод.

my_hash.try(:[], 'key1').try(:[], 'key2').try(:[], 'key3')

Другие используюти и

myhash['key1'].andand['key2'].andand['key3']

Некоторые люди думаютэгоцентрические ноль хорошая идея (хотя кто-то может выследить вас и замучить, если обнаружит, что вы это делаете).

class NilClass
  def method_missing(*args); nil; end
end

my_hash['key1']['key2']['key3']

Вы могли бы использоватьПеречислимые # уменьшить (или псевдоним вводить).

['key1','key2','key3'].reduce(my_hash) {|m,k| m && m[k] }

Или, возможно, расширить Hash или просто ваш целевой хеш-объект с помощью вложенного метода поиска

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']
Вы также можете попробовать монадический самоцвет, в котором есть Maybe (и другие монады), которые помогают в обработке исключений.
Синтаксис оператора безопасного навигатора по хэшам в моем предыдущем комментарии неверен. Правильный синтаксис:my_hash&.[]('key1')&.[]('key2')&.[]('key3').
Я решил сделать выборку подход. Но спасибо за все предложения. Nobita
Ты можешь использоватьdig метод для хеширования после Ruby 2.3,ruby-doc.org/core-2.3.0_preview1/Hash.html#method-i-dig
Что вы думаете об использованииrescue nil в конце заявления?
6

Объект # andand.

my_hash['key1'].andand['key2'].andand['key3']

Похожие вопросы