¿Hay un bucle" do do while " en Ruby?


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 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 do ... bucle 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?

 411
Author: Jeremy Ruten, 2008-09-26

10 answers

PRECAUCIÓN :

El begin <code> end while <condition> es rechazado por el autor de Ruby, Matz. En su lugar, sugiere usar Kernel#loop, por ejemplo,

loop do 
  # some code here
  break if <condition>
end 

Para más detalles, consulte: http://blade.nagaokaut.ac.jp/cgi-bin/scat.rb/ruby/ruby-core/6745 ( o vía Wayback), y esta wiki: http://rosettacode.org/wiki/Loops/Do-while#Ruby

 575
Author: Siwei Shen申思维,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2015-01-18 10:30:29

Encontré el siguiente fragmento mientras leía la fuente de Tempfile#initialize en la biblioteca Ruby core:

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 sería evaluado antes del contenido de begin...fin, pero ese no es el caso. Observe:

>> begin
?>   puts "do {} while ()" 
>> end while false
do {} while ()
=> nil

Como es de esperar, el bucle continuará ejecutándose mientras el modificador sea true.

>> n = 3
=> 3
>> begin
?>   puts n
>>   n -= 1
>> end while n > 0
3
2
1
=> nil

Aunque estaría feliz de no volver a ver esta expresión, comience...end es bastante poderoso. El siguiente es un modismo común para recordar un método de un solo trazador sin parámetros:

def expensive
  @expensive ||= 2 + 2
end

Aquí hay una manera fea, pero rápida de recordar 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 ha sido copiado aquí porque parece haber sido retirado del sitio de origen. También se pueden encontrar copias en el Archivo Web y en el Foro Ruby Buzz . - Bill el Lagarto

 185
Author: hubbardr,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2018-06-17 19:13:58

Así:

people = []

begin
  info = gets.chomp
  people += [Person.new(info)] if not info.empty?
end while not info.empty?

Referencia: El bucle oculto de Ruby do {} while ()

 99
Author: Blorgbeard,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2017-10-12 15:32:58

¿Qué tal esto?

people = []

until (info = gets.chomp).empty?
  people += [Person.new(info)]
end
 42
Author: AndrewR,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2008-09-25 23:38:42

Aquí está el artículo de texto completo del enlace muerto de hubbardr a mi blog.

Encontré el siguiente fragmento mientras leía la fuente de Tempfile#initialize en la biblioteca Ruby core:

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 sería evaluado antes que el contenido de begin...end, pero ese no es el caso. Observe:

>> begin
?>   puts "do {} while ()" 
>> end while false
do {} while ()
=> nil

Como es de esperar, el bucle continuará ejecutándose mientras el modificador sea true.

>> n = 3
=> 3
>> begin
?>   puts n
>>   n -= 1
>> end while n > 0
3
2
1
=> nil

Mientras que yo estaría feliz de nunca ver esta expresión de nuevo, begin...end es bastante poderoso. El siguiente es un modismo común para recordar 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 recordar 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
 11
Author: jvoorhis,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2013-08-04 17:08:05

Esto funciona correctamente ahora:

begin
    # statment
end until <condition>

Pero, puede ser removido en el futuro, porque la declaración begin es contraintuitiva. Véase: 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
 8
Author: Steely Wing,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2013-06-04 05:54:54

Por lo que deduzco, a Matz no le gusta la construcción

begin
    <multiple_lines_of_code>
end while <cond>

Porque, es semántica es diferente de

<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). Tomo 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 para las declaraciones if. En todos otros casos, el ordenador ejecuta código de izquierda a derecha(ej. || y &&) de arriba a abajo. Los humanos leen 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 se si esas sugerencias se analizarán con el resto del lenguaje. Pero en cualquier caso Prefiero mantener la ejecución de izquierda a derecha, así como la consistencia del lenguaje.

 5
Author: jds,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2014-11-13 09:36:18
a = 1
while true
  puts a
  a += 1
  break if a > 10
end
 3
Author: Paul Gillard,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2010-08-04 23:51:43

Aquí hay otro:

people = []
1.times do
  info = gets.chomp
  unless info.empty? 
    people += [Person.new(info)]
    redo
  end
end
 2
Author: Moray,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2011-11-10 12:38:58
ppl = []
while (input=gets.chomp)
 if !input.empty?
  ppl << input
 else
 p ppl; puts "Goodbye"; break
 end
end
 -3
Author: is_that_okay,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2010-01-11 18:47:58