Cap. 7 - Laços e Iteradores

Anterior Índice Próximo

Laços e iteradores…

A maior parte da atividade de programação está relacionada com repetição. Você pode querer que um programa bipe 10 vezes, leia linhas de um arquivo tantas quantas linhas existirem para serem lidas ou mostrar uma mensagem até que o usuário pressione uma tecla. O Ruby fornece várias formas de executar estes tipos de repetições.

Laços FOR

Em muitas linguagens de programação, quando você quer executar um pedaço de código um certo número de vezes você pode fazê­lo colocando o pedaço de código dentro de um laço for. Na maioria das linguagens, você tem que dar ao laço for uma variável com um valor inicial o qual é incrementado de 1 a cada volta do laço até que se atinja um valor final específico. Quando o valor final é atingido, o laço for termina a execução. Aqui está a versão deste tipo tradicional de laço for escrito em Pascal:
# Este é um código Pascal, não é Ruby!
For i := 1 to 3 do
  writeln( i );
                                            for_loop.r b
# Ruby Sample program from www.sapphiresteel.com / 
www.bitwisemag.com
puts( '­­­ loop #1 ­­­' )
for i in [1,2,3]  do 
        puts( i )
end
puts( '­­­ loop #3 ­­­' )
# 'do' is optional when for loop is 'multi­line'
for s in ['one','two','three'] #do 
        puts( s )
end

puts( '­­­ loop #3 ­­­' )

# 'do' is obligatory when for loop is on a single line
for x in [1, "two", [3,4,5] ] do puts( x ) end  

 

Você pode rever no Capítulo 5 (arrays) que o laço for do Ruby não trabalha exatamente desta forma! Em vez de fornecer um valor inicial e final, nós fornecemos ao laço for uma lista de itens e ele itera sobre eles, um a um, atribuindo o valor para a variável do laço até que se chegue ao final da lista.

Por exemplo, aqui está uma laço for que itera sobre seus itens em uma matriz, mostrando o valor a cada volta:

# Este é um código Ruby…
for i in [1, 2, 3] do
  puts( i )
end
 

O laço for é mais parecido com o iterador 'for each' existente em algumas outras linguagens. O autor do Ruby descreve o for como “açúcar sintático” para cada método each o qual é implementado por - tipos coleção - do Ruby como Arrays, Sets, Hashes e Strings ( uma String sendo, com efeito, uma coleção de caracteres ).

Para efeito de comparação, este é o laço for mostrado acima reescrito usando o método each:

[1, 2, 3].each do | i |
  puts( i )
end
 

Como você pode ver, não existe muita diferença.
each_loop.r b

# Ruby Sample program from www.sapphiresteel.com / 
www.bitwisemag.com
puts( '­­­ loop #1 ­­­' )
[1,2,3].each  do |i|
        puts( i )
end
puts( '­­­ loop #3 ­­­' )

['one','two','three'].each do |s|
       puts( s )
end
puts( '­­­ loop #3 ­­­' )

[1, "two", [3,4,5] ].each do |x| puts( x ) end  
Para converter o laço for em um iterador each, tudo o que fiz foi excluir o for e o in e anexar .each 
ao array. Então eu coloquei a variável do iterador, i, entre pipes (||).
# ii) each
['one', 'two', 'three'].each do |s|
  puts( s )
end
# ­­­ Example 2 ­­­
# i) for
for x in [1, “two”, [3,4,5]] do puts( x ) end
Note que a palavra­chave do é opcional em um laço for que se extende por múltiplas linhas mas é 
obrigatório quando ele é escrito em uma única linha:
# Aqui a palavra­chave 'do' pode ser omitida
for s in ['one', 'two', 'three']
  puts( s )
end

# Mas aqui é obrigatório
for s in ['one', 'two', 'three'] do puts( s ) end

omo escrever um laço for 'normal'...

Se você sentir saudades do tipo tr adicional do laço for, você sempr e pode 'imitá­lo' em Ruby usando um laço for para iter ar sobr e os valor es de uma faixa. Por exemplo, veja como usar uma variável par a o laço for par a contar de 1 até 10, mostrando o valor a cada volta do laço:

   for i in (1..10) do 
     puts( i )
   end

O qual pode ser r eescr ito usando each:

   (1..10).each do | i |
     puts( i )
   end

Note que a expressão da faixa, por exemplo 1..3, deve ser escrita entre parênteses, "()", quando é usada com o método each, senão o Ruby assume que você está tentando usar o each como um método do número final da faixa (um FixNum) em vez da expressão inteira ( uma faixa ). Os parênteses são opcionais quando uma faixa é usada no laço for. Quando iteramos sobre os itens usando each, o bloco de código entre o do e o end é chamado ( obviamente ) de 'bloco iterador'.

Parâm etros de Bloco: No Ruby quaisquer variáveis declaradas no topo do bloco são chamadas de “parâmetros do bloco”. Desta for ma, um bloco funciona como uma função e os parâmetros do bloco funcionam como a lista de argumentos da função. O método each executa o código inter no do bloco e passa par a ele os argumentos fornecidos por uma coleção ( por exemplo, uma matriz ).

Blocos

O Ruby tem uma sintaxe alternativa para delimitar blocos. Em vez de usar do..end, como abaixo..

# do..end
[[1,2,3],[3,4,5],[6,7,8]].each do 
  | a, b, c | 
    puts( “#{a}, #{b}, #{c}” )
end 
... você pode usar chaves {..} assim:
# chaves {..}
[[1,2,3],[3,4,5],[6,7,8]].each { 
  | a, b, c | 
    puts( “#{a}, #{b}, #{c}” )
}

Não importa qual delimitador você use, você deve assegurar­se que o delimitador de abertura do bloco, '{' ou 'do', seja colocado na mesma linha do método each. Colocar uma quebra de linha entre o método each e o delimitador de abertura do bloco é um erro de sintaxe.

Laços While

Ruby tem algumas outras formas de laços. Esta é como fazer um laço while:

while tired
  sleep
end

Ou, colocado de outra forma:

sleep while tired

Embora a sintaxe destes dois exemplos sejam diferentes, eles desempenham a mesma função.

No primeiro exemplo, o código entre while e end ( uma chamada para o método sleep ) executa enquanto a condição lógica ( a qual, neste caso, é o valor retornado pela chamada do método tired) for verdadeira. Como nos laços for a palavra­chave do pode, opcionalmente, ser colocada entre a condição de teste e o código a ser executado estiver em linhas separadas; a palavra-­chave do é obrigatória quando a condição de teste e o código a executar forem colocados na mesma linha.

Modificadores While

No segunda versão do laço ( sleep while tired ), o código a ser executado ( sleep ) precede a condição de teste ( while tired ). Esta sintaxe é chamada de um 'modificador while'. Quando você quer executar muitas expressões usando esta sintaxe, você pode colocá­las entre as palavras-­chave begin e end.

begin
  sleep
  snore
end while tired

Este é um exemplo mostrando as várias alternativas de sintaxe:

$hours_asleep = 0
def tired
  if $hours_asleep >= 8 then 
    $hours_asleep = 0
    return false
  else 
    $hours_asleep += 1
    return true
  end
end
def snore
  puts( 'snore...' )
end
def sleep
  puts( “z” * $hours_asleep )
end
while tired do sleep end # laço while em uma única linha
while tired                   # laço while em múltiplas linhas
  sleep
end 

sleep while tired                                # modificador while em uma única 
linha
begin                                      # modificador while em múltiplas linhas
  sleep
  snore
end while tired

O último exemplo acima ( modificador while em múltiplas linhas ) merece uma consideração maior já que introduz um novo comportamento. Quando um bloco de código delimitado por begin e end precede um teste while, o código sempre executa pelo menos uma vez. Nos outros tipos de teste while, o código pode nunca executar se a condição lógica inicialmente for falsa.

Assegurando que um laço execute pelo menos uma vez Usualmente, um laço while executa 0 ou mais vezes desde que o teste lógico seja avaliado antes que o laço execute; se o teste r etor na falso no início, o código inter no do laço não ser á executado. Porém, quando o teste while vem depois de um bloco de código delimitado por begin e end, o laço executar á 1 ou mais vezes já que a condição de teste é avaliada somente após o código inter no do laço executar . Par a ver ificar as difer enças de compor tamento destes dois tipos de laço while, r ode o pr ogr ama while2.rb. Estes exemplos devem ajudar no entendimento: x = 100 # o código neste laço nunca executa while ( x < 100 ) do puts('x < 100') end # o código neste laço nunca executa puts('x < 100') while ( x < 100 ) # mas o código neste laço executa uma vez begin puts('x < 100') end while ( x < 100 )

Laços Until

O Ruby também tem um laço until o qual pode ser entendido como uma laço 'while not'. Sua sintaxe e opções são as mesmas aplicadas ao while – isto é, o teste e o código a ser executado podem ser colocados em uma única linha ( neste caso a palavra­chave do é obrigatória ) ou eles podem ser colocados em linhas separadas ( neste caso o do é opcional ). Existe também um modificador until o qual permite você colocar o código antes da condição de teste; e existe, também, a opção de colocar o código entre um begin e end para assegurar que código execute pelo menos uma vez.

Aqui estão alguns exemplos simples de laços until:

i = 10
until i == 10 do puts( i ) end                                # nunca executa
until i == 10                                         # nunca executa
  puts( i ) 
  i += 1
end
puts( i ) until i == 10                               # nunca executa
begin                                       # executa uma vez
  puts(i)
end until i == 10

Ambos os laços while e until podem, assim como o laço for, ser usados para iterar sobre matrizes (arrays) e outras coleções. Por exemplo, o código abaixo mostra como iterar sobre todos os elementos de uma matriz:

while i < arr.length
  puts( arr[i] )
  i += 1
end
until i == arr.length
  puts( arr[i] )
  i += 1
end

Anterior Índice Próximo

-- LeandroNunes - 18 Oct 2006
Topic revision: r1 - 05 Jul 2008, UnknownUser
This site is powered by FoswikiCopyright © by the contributing authors. All material on this collaboration platform is the property of the contributing authors.
Ideas, requests, problems regarding Wiki-Colivre? Send feedback