Question

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" 

Je pensais que le mot-clé return était facultatif dans Ruby et que vous retourniez , que vous le demandiez ou non. Cela dit, je trouve surprenant que foo et bar aient une sortie différente, déterminée par le fait que foo contient un retour dans Proc f .

Quelqu'un sait-il pourquoi c'est le cas?

Était-ce utile?

La solution

Ruby a trois constructions:

  1. Un bloc n'est pas un objet et est créé par { ... } ou do . . end .
  2. Un proc est un objet Proc créé par Proc.new ou proc .
  3. Un lambda est un Proc créé par lambda (ou proc dans Ruby 1.8).

Ruby a trois mots clés qui retournent quelque chose:

  1. return met fin à la méthode ou à la méthode lambda dans laquelle il se trouve.
  2. next termine le bloc, proc ou lambda dans lequel il se trouve.
  3. break met fin à la méthode ayant abouti au bloc ou appelé le proc ou le lambda dans lequel il se trouve.

Dans lambdas, return se comporte comme suivant , quelle qu'en soit la raison. next et break sont nommés tels quels car ils sont le plus souvent utilisés avec des méthodes telles que each , où la fermeture du bloc entraînera l'itération reprenez avec l’élément next de la collection, et terminer chaque vous fera interrompre la boucle.


Si vous utilisez return dans la définition de foo , vous reviendrez de foo , même s'il se trouve dans un bloc ou un proc. Pour revenir d'un bloc, vous pouvez utiliser le mot-clé next à la place.

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"

Autres conseils

Ceci est la sémantique de Proc s; ce n'est pas nécessairement la sémantique de tous les blocs. Je suis d'accord c'est un peu déroutant. Il est là pour plus de flexibilité (et peut-être en partie parce que Ruby n’a pas de spécifications à part sa mise en œuvre).

Le comportement est défini dans l'implémentation Proc . Lambda se comporte différemment, donc si vous souhaitez que votre renvoie ne quitte pas la méthode englobante, utilisez lambdas . Sinon, omettez le mot clé return de votre Proc .

Une enquête approfondie sur les fermetures de Rubys est . C’est une exposition fantastique & # 233;.

Donc:

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) 

Pensez-y de cette façon: Proc.nouveau vient de créer un bloc de code faisant partie de la fonction appelante. proc / lambda crée une fonction anonyme comportant des liaisons spéciales. Quelques exemples de code aideront:

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

est équivalent à

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

  return "return from foo" 
end

il est donc clair que le retour va simplement revenir de la fonction 'foo'

en revanche:

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

est équivalent à (en ignorant les liaisons car non utilisé dans cet exemple):

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

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

Ce qui est aussi clair ne reviendra pas de foo et passera à l'instruction suivante.

Licencié sous: CC-BY-SA avec attribution
Non affilié à StackOverflow
scroll top