345 votes

Lors de l'utilisation de lambda, lors de l'utilisation de Proc.de nouveau?

En Ruby 1.8, il y a de subtiles différences entre proc/lambda d'une part, et Proc.new sur l'autre.

  • Quelles sont ces différences?
  • Pouvez-vous donner des lignes directrices sur la façon de décider lequel choisir?
  • En Ruby 1.9, proc et lambda sont différents. Quel est le problème?

383voto

Joey deVilla Points 4487

Une autre différence subtile mais importante est la manière dont les procs créé avec lambda et procs créé avec Proc.new gérer l' return déclaration:

  • En lambda-créé le proc, l' return instruction renvoie seulement à partir de la procédure elle-même
  • En Proc.new-créé le proc, l' return déclaration est un peu plus surprenant: il renvoie le contrôle non seulement de la proc, mais aussi de la méthode en joignant le proc!

Voici lambda-créé proc return dans l'action. Il se comporte d'une manière qui vous attend probablement à ce que:

def whowouldwin

Maintenant, voici un
-créé proc
faire la même chose. Vous êtes sur le point de voir un de ces cas où Ruby rompt le fameux Principe de moindre Surprise:

  mylambda = lambda {return "Freddy"}

Grâce à cet étonnant comportement (et à moins de frappe), j'ai tendance à privilégier l'aide d'
sur mylambda.call lors de la prise de procs.

95voto

Peter Wagenet Points 4069

Afin de fournir des précisions:

Joey dit que le retour de comportement de l' Proc.new est surprenant. Cependant, quand vous considérez que Proc.la nouvelle se comporte comme un bloc, ce n'est pas surprenant, c'est exactement la façon dont les blocs se comporter. lambas sur l'autre main se comportent plus comme des méthodes.

Ce fait explique pourquoi les Procs sont flexibles quand il s'agit d'arité (nombre d'arguments) alors qu'elles ne le sont pas. Les blocs de ne pas exiger de tous leurs arguments sont fournis, mais les méthodes ne sont (à moins qu'une valeur par défaut est fournie). Tout en fournissant lambda argument par défaut n'est pas une option en Ruby 1.8, il est maintenant pris en charge dans Ruby 1.9 avec l'alternative lambda syntaxe (comme indiqué par webmat):

concat = ->(a, b=2){ "#{a}#{b}" }
concat.call(4,5) # => "45"
concat.call(1)   # => "12"

Et Michiel de Mare (l'OP) est incorrect sur le Proc et lambda de se comporter de la même avec une arité de Ruby 1.9. J'ai vérifié qu'ils maintiennent encore le comportement de 1,8 comme indiqué ci-dessus.

break états ne fait pas beaucoup de sens dans les deux Procs ou lambdas. Dans le Procs, la rupture serait de retour vous de Proc.nouveau ce qui a déjà été réalisé. Et il ne ferait aucun sens de rompre avec un lambda puisqu'il s'agit essentiellement d'une méthode, et vous ne serait jamais pause de haut niveau d'une méthode.

next, redo, et raise se comportent de la même dans les deux Procs et les lambdas. Alors qu' retry n'est pas permis dans les deux et déclenche une exception.

Et enfin, l' proc méthode ne doit jamais être utilisé, car il est incompatible et a un comportement inattendu. En Ruby 1.8 il retourne en fait un lambda! En Ruby 1.9 cela a été corrigé et il renvoie un Proc. Si vous souhaitez créer un Proc, tenez - Proc.new.

Pour plus d'informations, je vous recommande fortement de O'Reilly Le Langage de Programmation Ruby , qui est ma source pour la plupart de cette information.

42voto

Mike Stone Points 21293

J'ai trouvé cette page qui montre quelle est la différence entre le Proc.nouveau et lambda sont. Selon la page, la seule différence est qu'un lambda est stricte sur le nombre d'arguments, il accepte, alors que le Proc.les nouveaux convertis arguments manquants à néant. Voici un exemple de la CISR session illustrant la différence:

l'irb(main):001:0> l = lambda { |x, y| x + y }
=> #<Proc:0x00007fc605ec0748@(cisr):1>
l'irb(main):002:0> p = Proc.nouveaux { |x, y| x + y }
=> #<Proc:0x00007fc605ea8698@(cisr):2>
l'irb(main):003:0> l.appel "hello", "world"
=> "helloworld"
l'irb(main):004:0> p.appel "hello", "world"
=> "helloworld"
l'irb(main):005:0> l.appel "bonjour"
ArgumentError: mauvais nombre d'arguments (1 de 2)
 à partir de (cisr):1
 à partir de (cisr):5: "appel"
 à partir de (cisr):5
 à partir de :0
l'irb(main):006:0> p.appel "bonjour"
TypeError: impossible de convertir le néant en Chaîne
 à partir de (cisr):2:`+'
 à partir de (cisr):2
 à partir de (cisr):6: "appel"
 à partir de (cisr):6
 à partir de :0

Cette page vous recommande l'utilisation de lambda sauf si vous souhaitez l'erreur tolérance de comportement. Je suis d'accord avec ce sentiment. À l'aide d'un lambda semble un peu plus concis, et avec une telle différence insignifiante, il semble que le meilleur choix dans la situation moyenne.

Comme pour Ruby 1.9, désolé, je n'ai pas regardé de 1,9 encore, mais je n'imagine pas qu'ils changeraient de tout cela beaucoup (ne prenez pas mon mot pour lui si, il semble que vous avez entendu parler de certains changements, donc je suis probablement trompé).

11voto

webmat Points 13359

Je ne peux pas en dire beaucoup sur les différences subtiles. Cependant, je peux souligner que Ruby 1.9, permet désormais de paramètres facultatifs pour les lambdas et des blocs.

Voici la nouvelle syntaxe pour le lacérateur lambdas en vertu de 1.9:

stabby = ->(msg='inside the stabby lambda') { puts msg }

Ruby 1.8 n'ont pas cette syntaxe. Ni la façon traditionnelle de les déclarer blocs/lambdas prise en charge args:

# under 1.8
l = lambda { |msg = 'inside the stabby lambda'|  puts msg }
SyntaxError: compile error
(irb):1: syntax error, unexpected '=', expecting tCOLON2 or '[' or '.'
l = lambda { |msg = 'inside the stabby lambda'|  puts msg }

Ruby 1.9, cependant, prend en charge les arguments optionnels, même avec l'ancienne syntaxe:

l = lambda { |msg = 'inside the regular lambda'|  puts msg }
#=> #<Proc:0x0e5dbc@(irb):1 (lambda)>
l.call
#=> inside the regular lambda
l.call('jeez')
#=> jeez

Si vous voulez construire Ruby1.9 pour de Léopard ou Linux, consultez cet article (sans vergogne l'auto-promotion).

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