Existe uma “fazer ... enquanto” loop no Ruby?
Pergunta
Eu estou usando este código para permitir que o usuário entra em nomes, enquanto o programa armazena-los em uma matriz até que eles entram uma string vazia (que deve pressionar ENTER após cada nome):
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 ficaria muito mais agradável em um do ... while loop:
people = []
do
info = gets.chomp
people += [Person.new(info)] if not info.empty?
while not info.empty?
Neste código que eu não tenho que informações atribuir a alguns seqüência aleatória.
Infelizmente este tipo de circuito não parece existir em Ruby. Alguém pode sugerir uma maneira melhor de fazer isso?
Solução
ATENÇÃO :
O begin <code> end while <condition>
é rejeitado pelo autor de Ruby Matz. Em vez disso, ele sugere o uso de Kernel#loop
, por exemplo.
loop do
# some code here
break if <condition>
end
Aqui está um troca de e-mail em 23 de novembro de 2005, onde Matz afirma:
|> 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>
rosettacode wiki tem uma história semelhante:
Durante novembro de 2005, Yukihiro Matsumoto, o criador do Ruby, lamentou esta funcionalidade loop e sugeriu o uso de Kernel # loop.
Outras dicas
Eu encontrei o seguinte trecho ao ler a fonte para
Tempfile#initialize
na biblioteca núcleo 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)
À primeira vista, eu assumi o modificador while seria avaliado antes do conteúdo de começar ... fim, mas que não é o caso. Observe:
>> begin ?> puts "do {} while ()" >> end while false do {} while () => nil
Como seria de esperar, o loop continuará a executar enquanto o modificador é verdade.
>> n = 3 => 3 >> begin ?> puts n >> n -= 1 >> end while n > 0 3 2 1 => nil
Enquanto eu ficaria feliz em nunca mais ver essa expressão de novo, começar ... final é bastante poderoso. O seguinte é uma expressão comum para memoize um método one-liner sem parâmetros:
def expensive @expensive ||= 2 + 2 end
Aqui está uma maneira feia, mas rápido para memoize algo mais complexo:
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 . O conteúdo foi copiado aqui porque parece ter sido retirado do local de origem. Cópias também podem ser encontradas no web Archive e em rubi zumbido Fórum . -Bill o Lagarto
Como esta:
people = []
begin
info = gets.chomp
people += [Person.new(info)] if not info.empty?
end while not info.empty?
Referência: Oculto de ruby ??do {} while () loop
Como sobre isso?
people = []
until (info = gets.chomp).empty?
people += [Person.new(info)]
end
Aqui está o texto completo do link morto de hubbardr ao meu blog.
eu encontrei o seguinte trecho ao ler a fonte para Tempfile#initialize
na biblioteca núcleo 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)
À primeira vista, eu assumi o modificador while
seria avaliado antes do conteúdo begin...end
, mas isso não é o caso. Observe:
>> begin
?> puts "do {} while ()"
>> end while false
do {} while ()
=> nil
Como seria de esperar, o loop continuará a executar enquanto o modificador é verdade.
>> n = 3
=> 3
>> begin
?> puts n
>> n -= 1
>> end while n > 0
3
2
1
=> nil
Enquanto eu ficaria feliz em nunca mais ver essa expressão novamente, begin...end
é bastante poderoso. O seguinte é uma expressão comum para memoize um método one-liner sem parâmetros:
def expensive
@expensive ||= 2 + 2
end
Aqui está uma maneira feia, mas rápido para memoize algo mais complexo:
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
Isso funciona corretamente agora:
begin
# statment
end until <condition>
Mas, pode ser remover no futuro, porque a instrução begin
é contra-intuitivo. Veja: http://blade.nagaokaut.ac .jp / cgi-bin / scat.rb / ruby ??/ ruby-core / 6745
Matz recomendado fazê-lo desta maneira:
loop do
# ...
break if <condition>
end
Pelo que pude perceber, Matz não gosta da construção
begin
<multiple_lines_of_code>
end while <cond>
porque, é semântica é diferente
<single_line_of_code> while <cond>
em que a primeira construção executa o código antes de verificar o estado, e a segunda construção testa a condição antes de ele executa o código (se). Eu levá-la Matz prefere manter a segunda construção porque combina uma construção de linha de comandos if.
Eu nunca gostei da segunda construção mesmo para se declarações. Em todos os outros casos, o computador código é executado da esquerda para a direita (eg. || e &&) de cima para baixo. Os seres humanos ler o código da esquerda para a direita de cima para baixo.
Eu sugiro as seguintes construções em vez disso:
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
Eu não sei se essas sugestões irá analisar com o resto da língua. Mas em qualquer caso I prefere mantendo esquerda para a direita de execução, bem como a consistência da linguagem.
a = 1
while true
puts a
a += 1
break if a > 10
end
Aqui está outra:
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