Existe-t-il un & # 8220; Faire & # 8230; tandis que & # 8221; boucle en rubis?
Question
J'utilise ce code pour permettre à l'utilisateur de saisir des noms pendant que le programme les stocke dans un tableau jusqu'à ce qu'ils entrent une chaîne vide (ils doivent appuyer sur entrée après chaque nom):
people = []
info = 'a' # must fill variable with something, otherwise loop won't execute
while not info.empty?
info = gets.chomp
people += [Person.new(info)] if not info.empty?
end
Ce code aurait l'air beaucoup plus beau dans une boucle do ... while:
people = []
do
info = gets.chomp
people += [Person.new(info)] if not info.empty?
while not info.empty?
Dans ce code, je n'ai pas à attribuer d'informations à une chaîne aléatoire.
Malheureusement, ce type de boucle ne semble pas exister en Ruby. Quelqu'un peut-il suggérer un meilleur moyen de le faire?
La solution
ATTENTION :
Le commence < code > se termine alors que < condition >
est rejeté par l'auteur de Ruby, Matz. Au lieu de cela, il suggère d'utiliser Kernel # loop
, par exemple
loop do
# some code here
break if <condition>
end
Voici un échange de courrier électronique dans le 23 nov 2005 où Matz déclare:
|> Don't use it please. I'm regretting this feature, and I'd like to
|> remove it in the future if it's possible.
|
|I'm surprised. What do you regret about it?
Because it's hard for users to tell
begin <code> end while <cond>
works differently from
<code> while <cond>
Le wiki RosettaCode a une histoire similaire:
En novembre 2005, Yukihiro Matsumoto, le créateur de Ruby, a regretté cette fonctionnalité de boucle et a suggéré d'utiliser la boucle Kernel #.
Autres conseils
J'ai trouvé l'extrait suivant lors de la lecture du code source de
Tempfile # initialize
dans la bibliothèque principale de Ruby:begin tmpname = File.join(tmpdir, make_tmpname(basename, n)) lock = tmpname + '.lock' n += 1 end while @@cleanlist.include?(tmpname) or File.exist?(lock) or File.exist?(tmpname)
À première vue, j'ai supposé que le modificateur while serait évalué avant le contenu de begin ... end, mais ce n'est pas le cas. Observez:
>> begin ?> puts "do {} while ()" >> end while false do {} while () => nil
Comme vous vous en doutez, la boucle continuera à s'exécuter tant que le modificateur est vrai.
>> n = 3 => 3 >> begin ?> puts n >> n -= 1 >> end while n > 0 3 2 1 => nil
Bien que je serais heureux de ne plus jamais revoir cet idiome, commencez… la fin est assez puissante. Ce qui suit est un idiome courant pour mémoriser une méthode one-liner sans paramètre:
def expensive @expensive ||= 2 + 2 end
Voici un moyen laid mais rapide de mémoriser quelque chose de plus complexe:
def expensive @expensive ||= begin n = 99 buf = "" begin buf << "#{n} bottles of beer on the wall\n" # ... n -= 1 end while n > 0 buf << "no more bottles of beer" end end
Initialement écrit par Jeremy Voorhis . Le contenu a été copié ici car il semble avoir été retiré du site d'origine. Des copies peuvent également être trouvées dans Archive Web et à Forum Ruby Buzz . -Bill the Lézard
Comme ceci:
people = []
begin
info = gets.chomp
people += [Person.new(info)] if not info.empty?
end while not info.empty?
Référence: La boucle cachée de Ruby {} While () Loop
Comment ça?
people = []
until (info = gets.chomp).empty?
people += [Person.new(info)]
end
Voici l'article en texte intégral du lien mort de hubbardr vers mon blog.
J'ai trouvé l'extrait suivant lors de la lecture du code source de Tempfile # initialize
dans la bibliothèque principale de Ruby:
begin
tmpname = File.join(tmpdir, make_tmpname(basename, n))
lock = tmpname + '.lock'
n += 1
end while @@cleanlist.include?(tmpname) or
File.exist?(lock) or File.exist?(tmpname)
À première vue, j'ai supposé que le modificateur tandis que
serait évalué avant le contenu de begin ... end
, mais ce n'est pas le cas. Observez:
>> begin
?> puts "do {} while ()"
>> end while false
do {} while ()
=> nil
Comme vous vous en doutez, la boucle continuera à s'exécuter tant que le modificateur est vrai.
>> n = 3
=> 3
>> begin
?> puts n
>> n -= 1
>> end while n > 0
3
2
1
=> nil
Même si je serais heureux de ne plus jamais revoir cet idiot, begin ... end
est assez puissant. Ce qui suit est un idiome courant pour mémoriser une méthode one-liner sans paramètre:
def expensive
@expensive ||= 2 + 2
end
Voici un moyen laid mais rapide de mémoriser quelque chose de plus complexe:
def expensive
@expensive ||=
begin
n = 99
buf = ""
begin
buf << "#{n} bottles of beer on the wall\n"
# ...
n -= 1
end while n > 0
buf << "no more bottles of beer"
end
end
Ceci fonctionne correctement maintenant:
begin
# statment
end until <condition>
Mais, il sera peut-être supprimé à l'avenir, car l'instruction begin
est contre-intuitive. Voir: http://blade.nagaokaut.ac .jp / cgi-bin / scat.rb / ruby ??/ ruby-core / 6745
Matz a recommandé de procéder ainsi:
loop do
# ...
break if <condition>
end
D'après ce que je comprends, Matz n'aime pas la construction
begin
<multiple_lines_of_code>
end while <cond>
car sa sémantique est différente de
<single_line_of_code> while <cond>
en ce que la première construction exécute le code avant de vérifier la condition, et la deuxième construction teste d'abord la condition avant d'exécuter le code (si jamais). Je suppose que Matz préfère conserver la deuxième construction, car elle correspond à une ligne de construction des instructions if.
Je n'ai jamais aimé la deuxième construction, même pour les déclarations if. Dans tous les autres cas, l'ordinateur exécute le code de gauche à droite (par exemple. || et & amp; & amp;) de haut en bas. Les humains lisent le code de gauche à droite de haut en bas.
Je suggère plutôt les constructions suivantes:
if <cond> then <one_line_code> # matches case-when-then statement
while <cond> then <one_line_code>
<one_line_code> while <cond>
begin <multiple_line_code> end while <cond> # or something similar but left-to-right
Je ne sais pas si ces suggestions seront analysées avec le reste du langage. Mais en tout cas Je préfère garder l'exécution de gauche à droite ainsi que la cohérence linguistique.
a = 1
while true
puts a
a += 1
break if a > 10
end
En voici un autre:
people = []
1.times do
info = gets.chomp
unless info.empty?
people += [Person.new(info)]
redo
end
end
ppl = []
while (input=gets.chomp)
if !input.empty?
ppl << input
else
p ppl; puts "Goodbye"; break
end
end