Pergunta

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" 

Eu pensei que o return palavra-chave era opcional em Ruby e que você está sempre returning se você solicitá-lo ou não. Dado que, acho que é surpreendente que foo e bar tem saída diferente determinada pelo fato de que foo contém um return explícito na Proc f.

Alguém sabe por que este é o caso?

Foi útil?

Solução

Ruby tem três construções:

  1. A bloco não é um objeto e é criado por { ... } ou do ... end.
  2. A proc é um objeto Proc criado por Proc.new ou proc.
  3. A lambda é um Proc criado por lambda (ou proc no Ruby 1.8).

Ruby tem três palavras-chave que o retorno de algo:

  1. return termina o método ou lambda é no.
  2. next termina o bloco, proc, ou lambda é no.
  3. break termina o método que passado para o bloco ou o chamado proc ou lambda é em.

Em lambdas, se comporta return como next, por qualquer motivo. next e break são nomeados a forma como eles são, porque eles são mais comumente usados ??com métodos como each, onde encerra o bloco fará com que a iteração para retomada na próxima elemento da coleção, e que encerra each causará você pausa fora do circuito.


Se você usar return dentro da definição de foo, você vai voltar a partir foo, mesmo que seja dentro de um bloco ou de um proc. Para retornar de um bloco, você pode usar a palavra-chave next vez.

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"

Outras dicas

Esta é a semântica para Procs; não é necessariamente a semântica para todos os blocos. Eu concordo que isso é um pouco confuso. É ali para flexibilidade adicional (e talvez parcialmente causa Ruby tem nenhuma especificação, excepto para a sua execução).

O comportamento é definido na implementação Proc. Lambdas comportar de maneira diferente, por isso, se você gostaria que seus returns não a saída para fora do método delimitador, uso lambdas . Ou, omitir a palavra-chave return do seu Proc.

A investigação profunda de Rubys fechamentos é aqui . É uma exposição fantástica.

Assim:

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) 

Pense nisso desta maneira: Proc.new apenas criar um bloco de código que faz parte da função de chamada. proc / LAMBDA criar uma função anônima que tem ligações especiais. A exemplos de código pouco vai ajudar:

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

é equivalente a

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

  return "return from foo" 
end

por isso, é claro que o retorno só vai retornar da função 'foo'

em contraste:

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

é equivalente a (ignorando as ligações, uma vez não utilizado neste exemplo):

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

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

O que é tão claramente não voltará a partir de foo e continuar para a próxima instrução em vez disso.

Licenciado em: CC-BY-SA com atribuição
Não afiliado a StackOverflow
scroll top