Estoy usando este código para permitir que el usuario ingrese nombres mientras el progtwig los almacena en una matriz hasta que ingresen una cadena vacía (deben presionar Enter 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 ciclo 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 una cadena aleatoria.
Desafortunadamente, este tipo de bucle no parece existir en Ruby. ¿Alguien puede sugerir una mejor manera de hacer esto?
PRECAUCIÓN :
El begin
end while
es rechazado por Matz, el autor de Ruby. En su lugar, sugiere usar Kernel#loop
, por ejemplo
loop do # some code here break if end
Para obtener más detalles, consulte: http://blade.nagaokaut.ac.jp/cgi-bin/scat.rb/ruby/ruby-core/6745 ( o vía Wayback ), y este wiki: http: // rosettacode. org / wiki / Loops / Do-while # Ruby
Encontré el siguiente fragmento mientras leía el origen de
Tempfile#initialize
en la biblioteca principal 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, supuse que el modificador while se evaluaría antes del contenido de begin … end, pero ese no es el caso. Observar:
>> begin ?> puts "do {} while ()" >> end while false do {} while () => nil
Como era de esperar, el ciclo continuará ejecutándose mientras el modificador sea verdadero.
>> n = 3 => 3 >> begin ?> puts n >> n -= 1 >> end while n > 0 3 2 1 => nil
Si bien me alegraría nunca volver a ver este idioma, comience … el final es bastante poderoso. El siguiente es un modismo común para memorizar un método de una línea sin params:
def expensive @expensive ||= 2 + 2 end
Esta es una forma 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
Escrito originalmente por Jeremy Voorhis . El contenido se ha copiado aquí porque parece haberse eliminado del sitio de origen. Las copias también se pueden encontrar en el Archivo web y en Ruby Buzz Forum . -Bill el lagarto
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
¿Qué tal esto?
people = [] until (info = gets.chomp).empty? people += [Person.new(info)] end
Aquí está el artículo completo del enlace muerto del hubbardr a mi blog.
Encontré el siguiente fragmento mientras leía el origen de Tempfile#initialize
en la biblioteca principal 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, supuse que el modificador while
se evaluaría antes del contenido de begin...end
, pero ese no es el caso. Observar:
>> begin ?> puts "do {} while ()" >> end while false do {} while () => nil
Como era de esperar, el ciclo continuará ejecutándose mientras el modificador sea verdadero.
>> n = 3 => 3 >> begin ?> puts n >> n -= 1 >> end while n > 0 3 2 1 => nil
Si bien me alegraría nunca volver a ver este idioma, begin...end
es bastante poderoso. El siguiente es un modismo común para memorizar un método de una línea sin params:
def expensive @expensive ||= 2 + 2 end
Esta es una forma 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
Esto funciona correctamente ahora:
begin # statment end until
Pero, puede eliminarse en el futuro, porque la statement de begin
es contraintuitiva. Ver: http://blade.nagaokaut.ac.jp/cgi-bin/scat.rb/ruby/ruby-core/6745
Matz recomienda hacerlo de esta manera:
loop do # ... break if end
Por lo que veo, a Matz no le gusta la construcción
begin end while
porque, es semántica es diferente de
while
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 es que lo hace). Supongo que Matz prefiere mantener el segundo constructo porque coincide con un constructo de línea de enunciados if.
Nunca me gustó el segundo constructo incluso para las declaraciones if. En todos los demás casos, la computadora ejecuta el código de izquierda a derecha (por ejemplo, || y &&) arriba a abajo. Los humanos leen el código de izquierda a derecha de arriba a abajo.
Sugiero los siguientes constructos en su lugar:
if then # matches case-when-then statement while then while begin end while # or something similar but left-to-right
No sé si esas sugerencias se analizarán con el rest del lenguaje. Pero, en cualquier caso, prefiero mantener la ejecución de izquierda a derecha y la consistencia del lenguaje.
a = 1 while true puts a a += 1 break if a > 10 end
Aqui hay otro más:
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