91 votes

Utiliser 'return' dans un bloc Ruby

Je suis en train d'utiliser Ruby 1.9.1 pour un langage de script incorporé, de sorte que "l'utilisateur final" le code est écrit en Ruby bloc. Un problème, c'est que je voudrais que les utilisateurs soient en mesure d'utiliser le "retour" de mots clés dans les blocs, ils n'ont pas besoin de s'inquiéter à propos de rendement implicite des valeurs. Avec cela à l'esprit, c'est le genre de chose que j'aimerais être capable de faire:

def thing(*args, &block)
  value = block.call
  puts "value=#{value}"
end

thing {
  return 6 * 7
}

Si j'utilise le 'retour' dans l'exemple ci-dessus, j'obtiens un LocalJumpError. Je suis conscient que c'est parce que le bloc en question est un Proc et pas un lambda. Le code fonctionne, si je retire le 'retour', mais je préfère vraiment être en mesure d'utiliser le 'retour' dans ce scénario. Est-ce possible? J'ai essayé de convertir le bloc à un lambda, mais le résultat est le même.

179voto

MBO Points 12516

Simplement utiliser next dans ce contexte:

$ irb
irb(main):001:0> def thing(*args, &block)
irb(main):002:1>   value = block.call
irb(main):003:1>   puts "value=#{value}"
irb(main):004:1> end
=> nil
irb(main):005:0>
irb(main):006:0* thing {
irb(main):007:1*   return 6 * 7
irb(main):008:1> }
LocalJumpError: unexpected return
        from (irb):7:in `block in irb_binding'
        from (irb):2:in `call'
        from (irb):2:in `thing'
        from (irb):6
        from /home/mirko/.rvm/rubies/ruby-1.9.1-p378/bin/irb:15:in `<main>'
irb(main):009:0> thing { break 6 * 7 }
=> 42
irb(main):011:0> thing { next 6 * 7 }
value=42
=> nil
  • return renvoie toujours à partir de la méthode, mais si vous testez ce code de la cisr vous n'avez pas de méthode, c'est pourquoi vous avez LocalJumpError
  • break retourne la valeur de la bloquer et se termine à son appel. Si votre bloc a été appelé par yield ou .call, alors break des pauses de cet itérateur trop
  • next retourne la valeur de la bloquer et se termine à son appel. Si votre bloc a été appelé par yield ou .call, alors next retourne la valeur de la ligne où l' yield a été appelé

21voto

molf Points 34978

Vous ne pouvez pas le faire en Ruby.

L' return mot-clé toujours des retours de la méthode ou lambda dans le contexte actuel. Dans les blocs, il sera de retour à partir de la méthode de fermeture a été défini. Il ne peut pas être prise pour un retour de l' appel de méthode ou lambda.

Le Rubyspec démontre que c'est en effet le comportement correct pour Ruby (admiddedly pas une réelle mise en œuvre, mais le but de la pleine compatibilité avec C Ruby):

describe "The return keyword" do
# ...
describe "within a block" do
# ...
it "causes the method that lexically encloses the block to return" do
# ...
it "returns from the lexically enclosing method even in case of chained calls" do
# ...

3voto

Simone Carletti Points 77653

Vous le regardez du mauvais point de vue. C'est un problème de thing , pas le lambda.

 def thing(*args, &block)
  block.call.tap do |value|
    puts "value=#{value}"
  end
end

thing {
  6 * 7
}
 

1voto

giorgian Points 2754

Où est la chose invoquée? Êtes-vous dans une classe?

Vous pouvez envisager d'utiliser quelque chose comme ceci:

 class MyThing
  def ret b
    @retval = b
  end

  def thing(*args, &block)
    implicit = block.call
    value = @retval || implicit
    puts "value=#{value}"
  end

  def example1
    thing do
      ret 5 * 6
      4
    end
  end

  def example2
    thing do
      5 * 6
    end
  end
end
 

Prograide.com

Prograide est une communauté de développeurs qui cherche à élargir la connaissance de la programmation au-delà de l'anglais.
Pour cela nous avons les plus grands doutes résolus en français et vous pouvez aussi poser vos propres questions ou résoudre celles des autres.

Powered by:

X