true - ¿Hay un bucle de "hacer... mientras" en Ruby?
times ruby (10)
Estoy usando este código para permitir que el usuario ingrese nombres mientras el programa los almacena en una matriz hasta que ingresen una cadena vacía (deben presionar ingresar después de cada nombre):
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
Este código se vería mucho mejor en un bucle do ... while:
people = []
do
info = gets.chomp
people += [Person.new(info)] if not info.empty?
while not info.empty?
En este código no tengo que asignar información a alguna cadena aleatoria.
Desafortunadamente, este tipo de bucle no parece existir en Ruby. ¿Alguien puede sugerir una mejor manera de hacer esto?
Encontré el siguiente fragmento de código mientras leía la fuente para
Tempfile#initialize
en la biblioteca central 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)
A primera vista, asumí que el modificador while se evaluaría antes que los contenidos de begin ... end, pero ese no es el caso. Observar:
>> begin ?> puts "do {} while ()" >> end while false do {} while () => nil
Como es de esperar, el bucle continuará ejecutándose mientras el modificador sea verdadero.
>> n = 3 => 3 >> begin ?> puts n >> n -= 1 >> end while n > 0 3 2 1 => nil
Aunque me encantaría no volver a ver este idioma, comenzar ... el final es bastante poderoso. El siguiente es un modismo común para memorizar un método de una sola línea sin parámetros:
def expensive @expensive ||= 2 + 2 end
Aquí hay una manera fea, pero rápida de memorizar algo más complejo:
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
Originalmente escrito por Jeremy Voorhis . El contenido se ha copiado aquí porque parece haber sido retirado del sitio de origen. Las copias también se pueden encontrar en el Archivo Web y en el Foro Ruby Buzz . -Bill the Lizard
¿Qué tal esto?
people = []
until (info = gets.chomp).empty?
people += [Person.new(info)]
end
Aquí está el artículo de texto completo del enlace muerto de hubbardr a mi blog.
Encontré el siguiente fragmento de código mientras leía la fuente para Tempfile#initialize
en la biblioteca central 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)
A primera vista, asumí que el modificador while
se evaluaría antes que los contenidos de begin...end
, pero ese no es el caso. Observar:
>> begin
?> puts "do {} while ()"
>> end while false
do {} while ()
=> nil
Como es de esperar, el bucle continuará ejecutándose mientras el modificador sea verdadero.
>> n = 3
=> 3
>> begin
?> puts n
>> n -= 1
>> end while n > 0
3
2
1
=> nil
Aunque me encantaría no volver a ver este idioma, begin...end
es bastante poderoso. El siguiente es un modismo común para memorizar un método de una sola línea sin parámetros:
def expensive
@expensive ||= 2 + 2
end
Aquí hay una manera fea, pero rápida de memorizar algo más complejo:
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
Aqui hay otro más:
people = []
1.times do
info = gets.chomp
unless info.empty?
people += [Person.new(info)]
redo
end
end
De lo que deduzco, a Matz no le gusta el constructo.
begin
<multiple_lines_of_code>
end while <cond>
Porque, es semántica es diferente a
<single_line_of_code> while <cond>
en que la primera construcción ejecuta el código primero antes de verificar la condición, y la segunda construcción prueba la condición primero antes de ejecutar el código (si alguna vez). Supongo que Matz prefiere mantener la segunda construcción porque coincide con una construcción de línea de sentencias if.
Nunca me gustó la segunda construcción, incluso si las declaraciones. En todos los demás casos, la computadora ejecuta el código de izquierda a derecha (por ejemplo, || y &&) de arriba a abajo. Los humanos leen el código de izquierda a derecha de arriba a abajo.
Sugiero las siguientes construcciones en su lugar:
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
No sé si esas sugerencias se analizarán con el resto del idioma. Pero en cualquier caso, prefiero mantener la ejecución de izquierda a derecha, así como la coherencia del lenguaje.
Esto funciona correctamente ahora:
begin
# statment
end until <condition>
Pero, puede ser eliminado en el futuro, porque la declaración begin
es contraintuitiva. Consulte: http://blade.nagaokaut.ac.jp/cgi-bin/scat.rb/ruby/ruby-core/6745
Matz recomendó hacerlo de esta manera:
loop do
# ...
break if <condition>
end
Me gusta esto:
people = []
begin
info = gets.chomp
people += [Person.new(info)] if not info.empty?
end while not info.empty?
Referencia: Ruby''s Hidden do {} while () Loop
PRECAUCION :
El begin <code> end while <condition>
es rechazado por el autor de Ruby, Matz. En su lugar, sugiere utilizar Kernel#loop
, por ejemplo
loop do
# some code here
break if <condition>
end
Para obtener más detalles, consulte: http://blade.nagaokaut.ac.jp/cgi-bin/scat.rb/ruby/ruby-core/6745 ( oa través de Wayback ), y este wiki: http://rosettacode.org/wiki/Loops/Do-while#Ruby
a = 1
while true
puts a
a += 1
break if a > 10
end
ppl = []
while (input=gets.chomp)
if !input.empty?
ppl << input
else
p ppl; puts "Goodbye"; break
end
end