Являются ли `return` и` break` бесполезными внутри блока Ruby при использовании в качестве обратного вызова? - PullRequest
3 голосов
/ 16 января 2011

В Rails блоки могут использоваться как обратные вызовы , например:

class User < ActiveRecord::Base
  validates_presence_of :login, :email

  before_create {|user| user.name = user.login.capitalize
    if user.name.blank?}
end

Когда используется такой блок, есть ли применение для break и return?Я спрашиваю, потому что обычно в блоке break вырывается из цикла, а return возвращается из метода включения.Но в контексте обратного вызова я не могу понять, что это значит.

Язык программирования Ruby предполагает, что return может вызвать LocalJumpError, но я несмог воспроизвести это в обратном вызове Rails.


Edit : со следующим кодом я бы ожидал LocalJumpError, но все, что делает return, это останавливаетвыполнение остальной части обратного вызова.

class User < ActiveRecord::Base
  validates_presence_of :login, :email

  before_create do |user|
    return
    user.name = user.login.capitalize
end

Ответы [ 2 ]

10 голосов
/ 16 января 2011

На самом деле это довольно интересно ...

Когда вы используете before_create в Rails 3, мы берем блок или лямбду, которые вы нам даете, и конвертируете их в метод.Затем мы вызываем метод с текущим объектом ActiveRecord для обратной совместимости со старым подходом Rails.

В результате, ваш фрагмент эквивалентен следующему:

class User < ActiveRecord::Base
  validates_presence_of :login, :email

  before_create do
    self.name = login.capitalize if name.blank?
  end
end

Из-за этогоПоведение, вы можете вызвать return из блока, и оно будет вести себя так же, как return в обычном методе (потому что - это нормальный метод).

В общем, continueв блоке «возвращается» из блока.

Специфическое поведение нормальных блоков:

  • Когда вы вызываете continue, вы пропускаете оставшуюся часть блока, ивозвращение управления методу, который вызвал блок.
  • Когда вы вызываете break, вы пропускаете оставшуюся часть блока, а также немедленно возвращаетесь из метода, который вызвал блок.

Вы можете видеть это поведение в обычных итераторах:

value = [1,2,3,4].each do |i|
  continue if i == 2
  puts i
end

В этом случае value будет [1,2,3,4], нормальное возвращаемое значение метода each, и результат будет:

1
3
4

В тСлучай прерывания:

value = [1,2,3,4].each do |i|
  break if i == 2
  puts i
end

В этом случае value будет nil, поскольку break также немедленно возвращается из метода each.Вы можете форсировать возврат с определенным значением, используя break n, что сделает value таким же, как n.Вывод в приведенном выше случае будет:

1

Важно то, что continue и break не применяются только к итераторам, хотя их семантика разработана так, чтобы вести себя как их эквиваленты в C вслучай итераторов.

3 голосов
/ 16 января 2011

Операция return внутри блоков Ruby зависит от того, был ли блок построен с Proc.new или lambda.

. Я рекомендую вам прочитать ответ с самым высоким рейтингом на этот другой вопрос переполнения стека: Когда использовать лямбду, когда использовать Proc.new?

В этом случае блок имеет свойства, созданные с помощью Proc.new.

Вызов return вконтекст такого рода обратного вызова имеет смысл только в том случае, если это также имеет смысл (чего, очевидно, нет):

class Foo
  return "bar"
end
...