Когда блоки более полезны, чем функции (ruby)? - PullRequest
6 голосов
/ 15 марта 2012

У меня есть два примера, которые дают одинаковый результат.

С блоком:

def self.do_something(object_id)
  self.with_params(object_id) do |params|
    some_stuff(params)
  end
end

def self.with_params(object_id, &block)
  find_object_by_id
  calculate_params_hash
  block.call(params_hash)
end

и методом:

def self.do_something(object_id)
  some_stuff(self.get_params(object_id))
end

def self.get_params(object_id)
  find_object_by_id
  calculate_params_hash
  params_hash
end

Второе решение кажется более простым, но я нашел некоторые варианты использования первого в коде нашего приложения. Мой вопрос: в какой ситуации рекомендуется первый? Каковы плюсы и минусы каждого из них?

Ответы [ 4 ]

3 голосов
/ 15 марта 2012

Обычно люди используют блоки, когда хотят запустить фрагмент кода внутри другого фрагмента кода. Примеры:

DB.with_shard_for_user(user_id) do |db|
  # perform operations on a user's shard

end # shard is reverted back to original value

File.new(filename) do |file|
  # work with file
end # file is closed automatically

User.transaction do
  # run some operations as a single transaction
end

Эти блоки закрыты в своем лексическом контексте (они захватывают переменные, из которых объявлен блок, и переносят их в место вызова блоков)

Схематическая структура метода, который принимает блок.

def transaction
  open_transaction # pre- part

  yield if block_given? # run provided code

  commit_transaction # post- part
rescue
  rollback_transaction # handle problems
end

В вашем первом примере использование блока, вероятно, неоправданно (IMHO). Слишком сложный без видимой причины.

2 голосов
/ 15 марта 2012

Основное различие между блоком и функцией согласно вашему примеру состоит в том, что блок выполняется в контексте вызывающей функции .

Так что, если ваш пример был:

def self.do_something(object_id)
  x = "boogy on"
  self.with_params(object_id) do |params|
    some_stuff(params)
    puts x
  end
end

Код в блоке может обращаться к переменной x, которая была определена вне блока. Это называется закрытием. Вы не могли бы сделать это, если бы вы просто вызывали функцию согласно второму примеру.

Еще одна интересная вещь о блоках - они могут влиять на поток управления внешней функцией. Так что можно сделать:

def self.do_something(object_id)
  self.with_params(object_id) do |params|
    if some_stuff(params)
        return
    end
  end

  # This wont get printed if some_stuff returns true.
  puts "porkleworkle"
end

Если вызов some_stuff в блоке возвращает истинное значение, блок вернется. Это вернется из блока и из метода дозирования . porkleworkle не получит вывод.

В ваших примерах вы не полагаетесь ни на одно из них, поэтому использование вызовов функций, вероятно, намного удобнее.

Однако во многих ситуациях использование блоков, позволяющих вам воспользоваться этими преимуществами, неоценимо.

1 голос
/ 15 марта 2012

Блок полностью зависит от вашего кода, но функция имеет свой собственный код.

Так что, если ваш код меняется в зависимости от ситуации, используйте блок.Если нет, создайте функцию и используйте ее как блок-блок.

1 голос
/ 15 марта 2012

Когда вы вызываете with_params (), вы не только отправляете данные, вы также предоставляете некоторый код для запуска. Посмотрите, отправляются ли разные блоки в вызов with_params ():

...
self.with_params(object_id) do |params|
  some_other_stuff()
  some_stuff(params)
end
...

и где-то еще:

...
self.with_params(object_id) do |params|
  even_more_stuff(params)
end
...

Если все блоки одинаковы или with_params () просто вызывается из одного места, то вы можете рассмотреть возможность удаления блоков.

Подводя итог: используйте блоки, если вы хотите передать в метод разные биты кода (блоки), а также данные: эй with_params, возьмите эти данные (object_id) и, кстати, запустите этот код (блок) пока вы на это.

Кстати, вы делаете разные вещи в двух примерах: with_params () возвращает

some_stuff(params_hash)

после оценки блока. И get_params () просто возвращает

params_hash
...