Почему явный возврат имеет значение в процессе?

StackOverflow https://stackoverflow.com/questions/1435743

  •  07-07-2019
  •  | 
  •  

Вопрос

def foo
  f = Proc.new { return "return from foo from inside proc" }
  f.call # control leaves foo here
  return "return from foo" 
end

def bar
  b = Proc.new { "return from bar from inside proc" }
  b.call # control leaves bar here
  return "return from bar" 
end

puts foo # prints "return from foo from inside proc" 
puts bar # prints "return from bar" 

Я думал, что return ключевое слово было необязательным в Ruby, и что вы всегда returnнезависимо от того, просите вы об этом или нет.Учитывая это, я нахожу удивительным, что foo и bar имеют разный результат, определяемый тем фактом, что foo содержит явный return в Proc f.

Кто-нибудь знает, почему это так?

Это было полезно?

Решение

Ruby имеет три конструкции:

  1. A блок не является объектом и создается { ... } или do ... end.
  2. A процесс является Proc объект, созданный Proc.new или proc.
  3. A лямбда является Proc созданный lambda (или proc в Ruby 1.8).

В Ruby есть три ключевых слова, которые возвращают что-то:

  1. return завершает работу метода или лямбды, в котором он находится.
  2. next завершает блок, процедуру или лямбду, в котором он находится.
  3. break завершает работу метода, который выдал блок или вызвал процедуру или лямбда-выражение, в котором он находится.

В лямбдах, return ведет себя как next, по какой бы то ни было причине. next и break названы так, как они есть, потому что они чаще всего используются с такими методами, как each, где завершение блока приведет к возобновлению итерации с Далее элемент коллекции и завершающий each это заставит вас перерыв вырванный из цикла.


Если вы используете return внутри определения foo, вы вернетесь из foo, даже если он находится внутри блока или процедуры.Чтобы вернуться из блока, вы можете использовать next ключевое слово вместо этого.

def foo
  f = Proc.new { next "return from foo from inside proc" }
  f.call # control leaves foo here
  return "return from foo" 
end
puts foo # prints "return from foo"

Другие советы

Это семантика для Procs;это не обязательно семантика для всех блоков.Я согласен, это немного сбивает с толку.Это делается для дополнительной гибкости (и, возможно, частично потому, что у Ruby нет спецификации, кроме как для его реализации).

Поведение определено в Proc реализация. Lambdaвы ведете себя по-другому, поэтому, если вы хотите, чтобы ваш returns не выходить вне заключающего метода используйте лямбды.Или опустите return ключевое слово из вашего Proc.

Глубокое исследование закрытий Rubys находится здесь.Это фантастическое разоблачение.

Итак:

def foo   
  f = Proc.new {
    p2 = Proc.new { return "inner proc"};
    p2.call
    return "proc"
  }
  f.call
  return "foo"
end

def foo2
  result = Proc.new{"proc"}.call
  "foo2 (proc result is: #{result})"
end

def bar
  l = lambda { return "lambda" }
  result = l.call
  return "bar (lambda result is: #{result})"
end

puts foo
# inner proc
puts foo2
# foo (proc result is: proc) 
puts bar
# bar (lambda result is: lambda) 

Подумайте об этом так: Proc.new просто создайте блок кода, который является частью вызывающей функции. proc / lambda создает анонимную функцию, которая имеет специальные привязки. Небольшой пример кода поможет:

def foo
  f = Proc.new { return "return from foo from inside Proc.new" }
  f.call # control leaves foo here
  return "return from foo" 
end

эквивалентно

def foo
  begin
    return "return from foo from inside begin/end" }
  end

  return "return from foo" 
end

поэтому ясно, что возвращение будет просто возвращено из функции 'foo'

в отличие от

def foo
  f = proc { return "return from foo from inside proc" }
  f.call # control stasy in foo here
  return "return from foo" 
end

эквивалентно (игнорируя привязки, так как не используется в этом примере):

def unonymous_proc
  return "return from foo from inside proc"
end

def foo
  unonymous_proc()
  return "return from foo" 
end

То, что очевидно, не вернется из foo и перейдет к следующему утверждению.

Лицензировано под: CC-BY-SA с атрибуция
Не связан с StackOverflow
scroll top