Руби идиома "возвращай, если не ноль" - PullRequest
15 голосов
/ 15 июня 2011

У меня такой вонючий метод, как:

def search_record(*args)    
  record = expensive_operation_1(foo)
  return record unless record.nil?

  record = expensive_operation_2(foo, bar)
  return record unless record.nil?

  record = expensive_operation_3(baz)
  return record unless record.nil?

  record = expensive_operation_4(foo, baz)
  return record unless record.nil?
end

Есть ли хорошая рубиновая идиома для "возврата результата вызова, если не ноль"?

Или мне просто написать return_unless_nil(&blk) метод?

(Обратите внимание, что аргументы разные для каждого вызова, поэтому я не могу просто перебрать их)

Ответы [ 2 ]

20 голосов
/ 15 июня 2011

Вас волнует разница между nil и false здесь?Если вас волнует, является ли возвращаемое значение каждого метода «ложным», то это довольно рубиновый способ сделать это:

def search_record(*args)    
  expensive_operation_1(foo)      ||
  expensive_operation_2(foo, bar) ||
  expensive_operation_3(baz)      ||
  expensive_operation_4(foo, baz)
end

Если вы не знакомы с этой идиомой, это можно объяснить таким образом: Ruby, как и большинство языков, "короткие замыкания" ИЛИ сравнения, что означает, что если первый операнд оценивается как "truey", он не потрудится вычислить второй операнд (т.е. если expensive_operation_1 возвращает что-то другоечем nil или false, он никогда не будет вызывать expensive_operation_2), потому что он уже знает, что результат логической операции имеет значение true.

Еще одна полезная вещь, которую делает Ruby вместовозвращая true или false из логических операций, он просто возвращает последний операнд, который он вычисляет.Таким образом, в этом случае, если expensive_operation_1 вернет nil, он вызовет expensive_operation_2, и если это вернет значение (не ложное), все выражение будет просто равно этому значению.

* 1020Наконец, мы можем связать эти логические значения так, что, по сути, он вернет результат первого операнда, который не является ложным, и никогда не оценит последующие операнды.Если все операндов оцениваются как ложные, он вернет последний операнд (который, как мы знаем, ложный и, в вашем случае, вероятно, nil).
2 голосов
/ 15 июня 2011

Дополняет ответ Джордана: давайте представим, что эти функции могут возвращать логическое значение (маловероятно для функции поиска, но в любом случае), а || не работает.Затем мы могли бы использовать рассмотренную здесь абстракцию :

expensive_operation_1(foo).or_if(:nil?) do
  expensive_operation_2(foo).or_if(:nil?) do
    expensive_operation_3(foo).or_if(:nil?) do
      expensive_operation_4(foo)
    end
  end
end
...