Neste artigo, serão exploradas as estruturas de repetição em Ruby, incluindo while, for e each, com exemplos práticos para facilitar o entendimento.
Apresentação
A partir de agora os programas que estão sendo desenvolvidos ganharão novas capacidades. Vamos pensar na pergunta: Como fazer um programa executar uma tarefa várias vezes sem precisar escrever o mesmo código várias vezes?
A resposta para essa pergunta está nas estruturas de repetição, elas servem para executar um mesmo trecho de código várias vezes, até que uma condição seja atendida (ou enquanto essa condição for verdadeira ou falsa, dependendo do tipo de estrutura usada).
Em outras palavras, você pode repetir o mesmo trecho de código quantas vezes forem necessárias, sem precisar escrever o código repetidamente. Para isso você cria uma estrutura de repetição que vai controlar quantas vezes o código será executado. Esse controle vai depender se a condição definida na estrutura de repetição for atendida ou não.
Enquanto a condição não for atendida, seja ela verdadeira ou falsa, o código dentro da estrutura de repetição continuará sendo executado por várias vezes automaticamente.
Imagine que você precisa lavar 50 pratos. Você não escreveria um manual de instruções dizendo:
- Lave o prato 1
- lave o prato 2
- lave o prato 3…
Assim vai até o prato 50. Isso seria muito cansativo e improdutivo (improdutivo é o mesmo que não produzir nada, ou seja, perder tempo).
Se você tivesse uma estrutura de repetição, você poderia dizer algo como:
- Enquanto houver pratos sujos, lave o próximo prato.
- Para cada prato sujo, lave o prato.
Estruturas de repetição são apenas formas de dizer ao computador: “Não pare ainda, continue trabalhando até que tal coisa aconteça”.
Observação: As estruturas de repetição também são chamadas de laços de repetição ou loops, com frequência até maior do que o termo estruturas de repetição. Então, se encontrar esses termos, saiba que eles significam a mesma coisa.
Tipos de laços de repetição em Ruby
No Ruby, existem dois tipos principais de laços:
- Os que se repetem enquanto uma condição for verdadeira ou falsa.
- Os que se repetem para cada item de uma coleção (como um array ou um hash).
Explicando melhor cada um desses tipos de laços:
- Laços que se repetem enquanto uma condição for verdadeira ou falsa: Esses laços fazem o mesmo comando várias vezes, desde que uma regra seja seguida. Por exemplo, dá para pedir ao usuário um número e só parar quando ele colocar um número correto.
- Exemplos desses laços são:
whileeuntil.
- Exemplos desses laços são:
- Laços que se repetem para cada item de uma coleção: Esses laços passam por todos os elementos de um grupo, como uma lista ou tabela, e fazem uma tarefa para cada um. Por exemplo, você pode usar um laço para mostrar cada nome de uma lista de nomes.
- Exemplos desses laços são:
foreeach.
- Exemplos desses laços são:
Laço while
O laço while é o laço mais intuitivo. Ele funciona com base em uma condição verdadeira. Enquanto a condição for verdadeira, o código dentro do laço será executado repetidamente.
Sintaxe do laço while
A sintaxe básica do laço while é a seguinte:
i = 0
while i < 5
puts i+1
i += 1
end
O que estamos fazendo aqui é:
i = 0
Cria uma variável chamada i e atribui o valor 0 a ela. Em programação, é muito comum usar a variável i para contar quantas vezes um laço foi executado.
O nome da variável i vem de “index” (índice, em inglês) ou “iterador” (que é algo que itera, ou seja, que repete uma ação várias vezes). A variável i será usada para controlar quantas vezes o laço será executado.
while i < 5
Inicia a estrutura de repetição. O computador vai fazer a pergunta: “O valor de i é menor que 5?” por várias vezes. Enquanto a resposta for “sim” (ou seja, enquanto a condição for verdadeira), o código dentro do laço será executado.
Como i foi inicializado com 0, a condição i < 5 é verdadeira, então o código dentro do laço será executado pela primeira vez.
puts i+1
Exibe o valor de i + 1 na tela. Na primeira vez que o laço é executado, i é 0, então o que será exibido é 1.
Em computação, a contagem começa do 0. Por isso, se colocar apenas puts i, a saída será:
0
1
2
3
4
Que são cinco números, mas começam do 0.
Mas, na contagem humana, a maioria das pessoas começa a contar do 1. Por isso, somamos 1 ao valor de i para exibir os números de 1 a 5.
Ao fazer puts i+1, você não altera o valor da variável i na memória, você apenas exibe o valor dela somado a 1.
Quando i é 0, imprime 1.
Quando i é 4, imprime 5.
i += 1
Essa linha é responsável por aumentar o valor da variável i em 1 a cada vez que o laço é executado. É uma forma abreviada de escrever i = i + 1.
A linha atualiza a variável de controle para avançar o laço. É uma linha muito importante, a mais importante, para evitar que o programa trave e que o laço entre no que é conhecido como “loop infinito”. O loop infinito acontece quando a condição do laço nunca se torna falsa, fazendo com que o laço continue executando para sempre.
Se o valor de i não for aumentado, ele continuará valendo 0 para sempre. Quando o código voltar para a linha while i < 5, a pergunta “O valor de i é menor que 5?” continuará sendo respondida com “sim”, e o laço nunca terminará. O programa ficaria preso nesse laço para sempre, travando o computador.
Ao fazer i += 1 (ou i = i + 1), o valor de i aumenta a cada vez que o laço é executado. Quando for executado a primeira vez, i será 1. Na segunda vez, i será 2, na terceira vez, i será 3, na quarta vez, i será 4, e na quinta vez, i será 5.
Então quando o código voltar para a linha while i < 5 pela sexta vez, a pergunta “O valor de i é menor que 5?” será respondida com “não”, e o laço terminará.
end
Finaliza o laço while. Tudo que estiver entre while e end faz parte do laço e será executado repetidamente enquanto a condição for verdadeira.
Cuidado ao usar < e <=
Em programação, é importante entender a diferença entre os operadores < (menor que) e <= (menor ou igual a).
Isso é ainda mais importante na hora de escrever as condições dos laços de repetição, para evitar erros que podem fazer o programa não funcionar como esperado.
Por exemplo, considere o seguinte código:
i = 0
while i <= 5
puts i
i += 1
end
Nesse caso, o laço while continuará executando enquanto i for menor ou igual a 5. Isso significa que o laço será executado quando i for 0, 1, 2, 3, 4 e também quando for 5 dando um total de 6 execuções.
Se você quiser que o laço execute apenas 5 vezes, deve usar o operador < (menor que) em vez de <= (menor ou igual a).
Essa diferença pode parecer pequena, mas é muito, muito importante para garantir que o programa funcione corretamente.
Executar pelo menos uma vez com begin…end while
Existem situações em que você quer que o código dentro do laço seja executado pelo menos uma vez, mesmo que a condição inicial seja falsa. Para isso, você pode usar a estrutura begin...end while.
Por exemplo, vamos criar um menu simples que será exibido pelo menos uma vez, e continuará sendo exibido enquanto o usuário não escolher a opção de sair:
opcao = ""
begin
puts "Menu:"
puts "1. Opção 1"
puts "2. Opção 2"
puts "3. Sair"
opcao = gets.chomp
end while opcao != "3"
Aqui, o menu será exibido pelo menos uma vez, e continuará sendo exibido enquanto a pessoa não digitar “3” para sair.
Laço until
O laço until é o oposto do laço while. Ele executa o código dentro do laço enquanto a condição for falsa. Quando a condição se torna verdadeira, o laço termina.
Sintaxe do laço until
A sintaxe básica do laço until é a seguinte:
bateria = 0
# Tradução: ATÉ QUE a bateria seja 100...
until bateria == 100 do
puts "Carregando... #{bateria}%"
bateria += 10
end
puts "Carga completa! Bateria em #{bateria}%"
O que estamos fazendo aqui é:
bateria = 0
Cria uma variável chamada bateria e atribui o valor 0 a ela. Essa variável será usada para simular o nível de carga da bateria.
until bateria == 100 do
Inicia a estrutura de repetição. O computador vai fazer a pergunta: “O valor de bateria é igual a 100?” por várias vezes. Enquanto a resposta for “não” (ou seja, enquanto a condição for falsa), o código dentro do laço será executado.
Como bateria foi inicializado com 0, a condição bateria == 100 é falsa, então o código dentro do laço será executado pela primeira vez.
puts "Carregando... #{bateria}%"
Exibe o nível atual de carga da bateria na tela. Na primeira vez que o laço é executado, bateria é 0, então o que será exibido é “Carregando… 0%”.
bateria += 10
Essa linha é responsável por aumentar o valor da variável bateria em 10 a cada vez que o laço é executado. É uma forma abreviada de escrever bateria = bateria + 10.
Ao fazer bateria += 10 (ou bateria = bateria + 10), o valor de bateria aumenta a cada vez que o laço é executado. Quando for executado a primeira vez, bateria será 10. Na segunda vez, bateria será 20, na terceira vez, bateria será 30, na quarta vez, bateria será 40, e assim por diante, até chegar a 100.
end
Finaliza o laço until. Tudo que estiver entre until e end faz parte do laço e será executado repetidamente enquanto a condição for falsa.
puts "Carga completa! Bateria em #{bateria}%"
Exibe uma mensagem indicando que a carga da bateria está completa, mostrando o valor final da variável bateria, que será 100 quando o laço terminar.
Exemplos com until
Observe os seguintes códigos que utilizam o laço until:
i = 0
until i == 3
puts i+1
i += 1
end
i = 0
until i <= 3
puts i+1
i += 1
end
i = 0
until i < 3
puts i+1
i += 1
end
O que vai acontecer em cada um desses códigos? Vamos analisar cada um deles:
-
Em
until i == 3, o laço continuará executando enquantoinão for igual a 3 (ou seja, enquanto a condição for falsa). Portanto, ele imprimirá os números 1, 2 e 3 na tela por causa doputs i+1. -
Em
until i <= 3, nada será mostrado na tela. Isso porque a condiçãoi <= 3já é verdadeira desde o início (poisicomeça em 0 e 0 é menor que 3). Como a condição já começou verdadeira e o laçountilsó executa enquanto a condição for falsa, o código dentro do laço nunca será executado. -
O mesmo vai acontecer em
until i < 3. A condiçãoi < 3já é verdadeira desde o início (poisicomeça em 0 e 0 é menor que 3). Portanto, o código dentro do laço nunca será executado, e nada será mostrado na tela.
Dica sobre while e until
Use o laço while quando quiser que o código seja executado enquanto uma condição for verdadeira até que ela se torne falsa.
Já o laço until deve ser usado quando quiser que o código seja executado enquanto uma condição for falsa até que ela se torne verdadeira.
Para qualquer laço, não apenas while e until, o mais importante é ter certeza que a condição que você criou para o laço vai mudar em algum momento, para evitar que o laço entre em um loop infinito. Sempre atualize a variável de controle dentro do laço para garantir que a condição será eventualmente atendida e o laço terminará.
Sempre respeite a lógica do seu programa na hora de definir as condições dos laços. Por exemplo, na hora de definir seus operadores lógicos (<, <=, ==, etc.), escolha o operador que faz sentido para o que você quer alcançar com o laço.
Laço for
O laço for serve para passar por todos os itens de uma coleção (lista) de elementos, como um array ou range (intervalo de números). Para cada item dessa coleção (lista), o código que está dentro do laço é executado.
Sintaxe do laço for
A sintaxe básica do laço for é a seguinte:
idades = [10, 22, 35, 46, 57]
nomes = ["Ana", "Bruno", "Carla", "Daniel", "Eva"]
i = 0
for i in 0..4
puts "#{i+1}ª execução do laço for."
puts "#{nomes[i]} tem #{idades[i]} anos."
end
O que estamos fazendo aqui é um exemplo clássico de iteração (repetição) sobre dois arrays (listas) ao mesmo tempo, usando o laço for.
Primeiro idades = [10, 22, 35, 46, 57] cria um array chamado idades que contém cinco números representando idades.
Depois nomes = ["Ana", "Bruno", "Carla", "Daniel", "Eva"] cria outro array chamado nomes que contém cinco strings representando nomes.
Imagine esses dois arrays como duas listas paralelas, duas colunas em uma tabela do Excel, onde o primeiro nome corresponde à primeira idade, o segundo nome à segunda idade, e assim por diante.
As colunas estão alinhadas, ou seja, a informação que está na primeira posição de um array corresponde à informação que está na primeira posição do outro array. Como em uma tabela:
| Nome | Idade |
|---|---|
| Ana | 10 |
| Bruno | 22 |
| Carla | 35 |
| Daniel | 46 |
| Eva | 57 |
Então o laço for i in 0..4 inicia a estrutura de repetição.
for i in 0..4
É como dizer ao computador:
“Para a nossa variável contadora i (que é como nosso dedo nossa maneira de apontar) repita os comandos do código abaixo começando com i = 0 e terminando com i = 4. A cada vez que o laço for executado o i deve mudar de valor e o código do laço deve ser executado de novo.”
O que o computador entende é:
“Vou executar o código a seguir 5 vezes. Na primeira vez, o i vale 0. Na segunda vez o i, vale 1. Na terceira vez o i vale 2. Na quarta vez o i vale 3. Na quinta e última vez o i vale 4.”
Então dentro do laço de repetição, temos dois comandos puts. O primeiro comando:
puts "#{i+1}ª execução do laço for."
Exibe na tela a mensagem indicando qual é a execução atual do laço, somando 1 ao valor de i para começar a contagem do 1.
Quando o i for 0, exibirá “1ª execução do laço for.”
Quando o i for 1, exibirá “2ª execução do laço for.”
E assim por diante, até a 5ª execução. Isso é apenas para ficar bonito na tela, não altera os dados das listas.
Já o segundo comando:
puts "#{nomes[i]} tem #{idades[i]} anos."
Exibe na tela o nome e a idade correspondentes, usando o valor de i para acessar os elementos corretos em cada array.
Por exemplo, quando i for 0, ele acessa nomes[0] (que é “Ana”) e idades[0] (que é 10), exibindo “Ana tem 10 anos.”
A simulação completa desse laço for resultará no seguinte:
| Número de execução do laço | Cálculo | Saída exibida |
|---|---|---|
| 1ª execução (i = 0) | Cálculo: i+1 vira 1. Acesso: nomes[0] é Ana, idades[0] é 10. | 1ª execução do laço for. Ana tem 10 anos. |
| 2ª execução (i = 1) | Cálculo: i+1 vira 2. Acesso: nomes[1] é Bruno, idades[1] é 22. | 2ª execução do laço for. Bruno tem 22 anos. |
| 3ª execução (i = 2) | Cálculo: i+1 vira 3. Acesso: nomes[2] é Carla, idades[2] é 35. | 3ª execução do laço for. Carla tem 35 anos. |
| 4ª execução (i = 3) | Cálculo: i+1 vira 4. Acesso: nomes[3] é Daniel, idades[3] é 46. | 4ª execução do laço for. Daniel tem 46 anos. |
| 5ª execução (i = 4) | Cálculo: i+1 vira 5. Acesso: nomes[4] é Eva, idades[4] é 57. | 5ª execução do laço for. Eva tem 57 anos. |
Usando for com arrays diretamente
Se você não precisar conectar dois arrays (listas) diferentes, pode usar o laço for diretamente com um array.
Veja o exemplo abaixo:
idades = [10, 22, 35, 46, 57]
# para cada idade na lista de idades faça:
for idade in idades
puts "Idade: #{idade} anos."
end
Aqui, você não se preocupa em saber “onde” o item está (posição 0, 1, 2…), você só quer saber “o que” é o item.
Neste caso, a leitura do código é muito natural: “Para cada valor que estiver dentro da lista idades, chame esse valor temporariamente de idade e execute o código”.
A variável idade (no singular) é criada automaticamente pelo laço. Ela serve como uma “gaveta temporária” que guarda um valor diferente a cada volta do laço.
Comparando com uma playlist de música:
- Usando índice (i) como foi feito antes: É como dizer “Toque a música da faixa 1”, depois “Toque a música da faixa 2”. Você precisa saber o número da faixa para escolher a música.
- Usando o array diretamente (este exemplo): É como apertar o botão “Próxima”. Você não precisa saber qual é o número da faixa, apenas ouve a música que está tocando agora e passa para a seguinte automaticamente.
Usando for com ranges
O Range (intervalo) é um tipo de dado no Ruby que representa uma sequência de valores, geralmente números. É muito útil quando você quer repetir alguma coisa um número específico de vezes, mas não tem uma lista pronta.
A sintaxe é muito simples: você coloca o valor inicial, dois pontos (..) e o valor final.
Observe o exemplo:
# Vai contar de 1 até 5
for numero in 1..5
puts "Contando: #{numero}"
end
A saída será:
Contando: 1
Contando: 2
Contando: 3
Contando: 4
Contando: 5
Diferença entre dois pontos (..) e três pontos (…)
Existe um detalhe importante nos intervalos do Ruby:
1..5(dois pontos): Inclui o último número. Vai de 1 até 5 (1, 2, 3, 4, 5).1...5(três pontos): Exclui o último número. Vai de 1 até quase 5 (1, 2, 3, 4).
Exemplo com três pontos:
# Vai contar de 1 até 4 (o 5 fica de fora)
for numero in 1...5
puts "Contando: #{numero}"
end
A saída será:
Contando: 1
Contando: 2
Contando: 3
Contando: 4
Isso é útil quando você quer evitar ultrapassar um limite específico.
Laço each
O laço each é a forma mais utilizada e “rubista” de fazer repetições em coleções. Enquanto o for é comum em muitas linguagens de programação (como C, Java, Python), o each é mais específico do Ruby e é preferido pela comunidade Ruby por ser mais elegante (para a comunidade Ruby, “elegante” significa “bonito e eficiente”).
A palavra “each” significa “cada”. A leitura é: “Para cada item da coleção, faça isso”.
A estrutura each é diferente do for. Aqui, o laço é um método que pertence as coleções (“array”, “range”, “hash”).
Devemos lembrar do que já foi dito em outros artigos: método = ação de um objeto.
Ou seja, o each é uma ação dos arrays (listas), ranges (intervalos) e hashes (tabelas) que faz o seguinte: “Para cada item da coleção, execute o código que está dentro do bloco.”
No caso do for, o laço é uma estrutura de controle da linguagem Ruby. As coleções estão lá paradas e o laço for passa por elas executando o código dentro do laço para cada item da coleção.
No caso do each, as coleções (arrays, ranges, hashes) têm o método each que faz o trabalho de passar por cada item da coleção e executar o código dentro do bloco. Ou seja, é a própria coleção (que é um objeto) que executa a ação de iterar (repetir) o código para cada um dos seus itens.
-
for: Estrutura de controle da linguagem Ruby que itera sobre coleções.
-
each: Método dos objetos coleção (arrays, ranges, hashes) que itera sobre seus próprios itens.
Sintaxe do laço each
nomes = ["Ana", "Bruno", "Carla"]
nomes.each do |nome|
puts "Olá, #{nome}!"
end
Vamos entender as partes dessa estrutura:
-
nomes.each: Você pega a lista (nomes) e chama o método.each(ponto each). É como dar uma ordem para a lista: “Lista, para cada item seu, faça…” -
do ... end: Isso define um bloco de código. Tudo que estiver entre odoe oendserá executado para cada item. -
|nome|: As barras verticais (pipes) funcionam como a “gaveta temporária”. O Ruby pega o item atual da lista e o coloca dentro da variável que você escreveu entre as barras. Você pode dar qualquer nome para essa variável (como|pessoa|,|item|,|x|). -
puts "Olá, #{nome}!": Esse é o código que será executado para cada item. Aqui, ele exibe uma saudação personalizada usando o nome atual da lista.
A saída desse código será:
Olá, Ana!
Olá, Bruno!
Olá, Carla!
Sintaxe de uma linha (Blocos Inline)
Uma das características mais amadas do Ruby é a capacidade de escrever códigos concisos (conciso é o mesmo que breve ou resumido). Se o código dentro do bloco for curto (apenas uma linha), você pode substituir o do...end por chaves { ... }.
Veja como fica o exemplo anterior em uma única linha:
nomes = ["Ana", "Bruno", "Carla"]
nomes.each { |nome| puts "Olá, #{nome}!" }
O resultado é exatamente o mesmo, mas economiza espaço vertical na tela. Mas, cuidado para não exagerar! Se o código dentro do bloco for muito longo, é melhor usar o formato com do...end para manter a legibilidade.
Usando each com Hashes
O each é poderoso porque funciona em qualquer coleção. Nos Hashes (que são como dicionários com chave e valor), o bloco recebe duas variáveis: uma para a chave e outra para o valor.
# Criando um Hash com produtos e preços
produtos = { "Camiseta" => 29.90, "Calça" => 89.90, "Meia" => 9.90 }
produtos.each do |produto, preco|
puts "O item #{produto} custa R$ #{preco}"
end
Observe que usamos |produto, preco| entre as barras verticais. O Ruby entende automaticamente que o primeiro item é a chave (nome do produto) e o segundo item é o valor (preço do produto).
E se eu precisar do índice? (each_with_index)
Às vezes, quando você está passando por cada item de uma lista (iterando) usando o each no Ruby, pode querer saber em que lugar aquele item está, ou seja, seu número na lista (índice). Para isso, existe o método each_with_index, que mostra o índice de cada item enquanto você percorre a coleção seja ela um array ou um hash.
O exemplo a seguir mostra como usar o each_with_index com um array:
frutas = ["Maçã", "Banana", "Cereja"]
frutas.each_with_index do |fruta, indice|
puts "#{indice + 1}: #{fruta}"
end
Aqui, o bloco recebe dois parâmetros (|fruta, indice|): o nome da fruta e seu índice na lista. Note que somamos 1 ao índice para começar a contagem do 1, já que os índices em programação começam do 0.
A saída será:
1: Maçã
2: Banana
3: Cereja
Você também pode usar o each_with_index com hashes. Veja o exemplo:
pessoas = { "Ana" => 25, "Bruno" => 30, "Carla" => 28 }
pessoas.each_with_index do |(nome, idade), indice|
puts "#{indice + 1}: #{nome} tem #{idade} anos."
end
Neste caso, o bloco recebe uma tupla, tupla é um grupo de valores, nesse caso o grupo de valores é o nome, a idade e o índice. A saída será:
1: Ana tem 25 anos.
2: Bruno tem 30 anos.
3: Carla tem 28 anos.
Então, o each_with_index é uma ferramenta muito útil quando você precisa tanto do valor quanto da posição do item na coleção enquanto itera sobre ela.
Laço times
Esse é um método exclusivo dos números inteiros (Integer) no Ruby. É a maneira mais fácil de dizer “Repita isso X vezes”. Não precisa criar uma variável para contar, como i = 0.
Como funciona? Você pega um número inteiro e chama o método times nele, passando um bloco de código que será executado esse número de vezes.
Sintaxe do laço times
Exemplo:
5.times do |i|
puts "Esta é a execução número #{i + 1}"
end
Aqui, o número 5 indica que o bloco de código dentro do do...end será executado 5 vezes. A variável i dentro das barras verticais (|i|) representa o índice da execução atual, começando do 0, é apenas para mostrar qual é a execução atual.
A saída será:
Esta é a execução número 1
Esta é a execução número 2
Esta é a execução número 3
Esta é a execução número 4
Esta é a execução número 5
Outro exemplo com times:
3.times { puts "Repetindo esta mensagem!" }
Aqui, o bloco de código é simples e cabe em uma única linha, então usamos as chaves { ... } para definir o bloco. A mensagem “Repetindo esta mensagem!” será exibida 3 vezes.
Use o times quando você souber exatamente o número de repetições necessárias e não estiver percorrendo uma lista complexa.
Laços de repetição em uma frase
| Laço | Frase para lembrar |
|---|---|
while |
"Enquanto for verdade... faça isso." |
until |
"Até que seja verdade... faça isso." |
for |
"Para cada item na lista... faça isso." |
each |
"Para cada item nessa lista... faça isso." |
times |
"Repita isso X vezes." |
Refazendo exercícios de artigos anteriores
Agora que os laços de repetição foram apresentados, serão refeitos alguns exercícios dos artigos anteriores, mas dessa vez utilizando laços de repetição para resolver os problemas.
Assim será possível ver como os laços de repetição podem facilitar a resolução de problemas que envolvem tarefas repetitivas.
Otimizando o menu de pagamento
No exercício original, se a pessoa digitasse uma opção inválida, o programa apenas dizia “Opção inválida” e encerrava. Com o while, podemos obrigar a pessoa a ficar no menu até escolher uma opção correta.
Código atualizado:
preco = 0.0
opcao = 0
print "Digite o preço normal do produto: "
preco = Float(gets.chomp)
# Otimização: O programa fica preso aqui ENQUANTO a opção for inválida
# (menor que 1 OU maior que 4)
while opcao < 1 || opcao > 4
puts "\n--- Escolha a condição de pagamento ---"
puts "1 - À vista em dinheiro (10% de desconto)"
puts "2 - À vista no cartão (15% de desconto)"
puts "3 - Em duas vezes (sem juros)"
puts "4 - Em duas vezes (10% de juros)"
print "Escolha uma opção: "
opcao = Integer(gets.chomp) rescue 0 # 'rescue 0' evita erro se digitar letras
if opcao < 1 || opcao > 4
puts "Opção inválida! Tente novamente."
end
end
# Daqui para baixo, sabemos que a opção é válida (1, 2, 3 ou 4)
case opcao
when 1
puts "Valor final: R$ #{(preco * 0.90).round(2)}"
when 2
puts "Valor final: R$ #{(preco * 0.85).round(2)}"
when 3
puts "Valor final: R$ #{preco.round(2)} (2x de R$ #{(preco/2).round(2)})"
when 4
total = preco * 1.10
puts "Valor final: R$ #{total.round(2)} (2x de R$ #{(total/2).round(2)})"
end
Aqui, o laço while mantém o programa no menu de pagamento até que a pessoa escolha uma opção válida (1, 2, 3 ou 4). Se a opção for inválida, ele exibe uma mensagem e pede para tentar novamente.
Entendendo o rescue 0:
No código acima, usamos Integer(gets.chomp) rescue 0. Isso serve para tratar erros de digitação.
- Se a pessoa digitar um número (exemplo: “3”), o
Integerconverte para o número 3. - Se a pessoa digitar uma letra (exemplo: “a”), o
Integernormalmente daria um erro e fecharia o programa. - O
rescue 0diz ao Ruby: “Se der erro ao tentar converter, não feche o programa. Em vez disso, use o valor 0”. - Como 0 é uma opção inválida no nosso menu (que vai de 1 a 4), o laço
whilecontinua rodando e pede a pessoa para escolher a opção novamente.
Validando dados do empréstimo
No exercício de empréstimo original, verificamos idade e renda uma única vez. Aqui, vamos usar o until para garantir que a renda informada seja válida (maior que zero). O until é ótimo para ler como “Faça isso ATÉ QUE a condição seja satisfeita”.
Código atualizado:
renda = 0.0
print "Digite sua idade: "
idade = Integer(gets.chomp)
# Otimização: Repete a pergunta ATÉ QUE a renda seja maior que 0
until renda > 0 do
print "Digite sua renda mensal (deve ser maior que zero): "
renda = Float(gets.chomp) rescue 0.0
if renda <= 0
puts "Valor inválido. Por favor, informe uma renda real."
end
end
# Restante da lógica simplificada para o exemplo
print "Digite o valor do empréstimo: "
valor_emprestimo = Float(gets.chomp)
if valor_emprestimo > (renda * 15) || idade < 18
puts "Empréstimo Negado."
else
puts "Empréstimo Pré-Aprovado! (Sujeito a análise de crédito)."
end
Aqui, o laço until mantém o programa pedindo a renda até que a pessoa informe um valor maior que zero. Se a renda for inválida (menor ou igual a zero), ele exibe uma mensagem e pede para tentar novamente.
Também usamos rescue 0.0 para evitar erros se a pessoa digitar algo que não seja um número.
Ordenando números dinamicamente
O exercício original pedia 3 números usando variáveis soltas (n1, n2, n3). E se fossem 10 números? Com .times coletamos os dados e com .each mostramos o resultado.
numeros = []
puts "Vamos ordenar 3 números!"
# Otimização 1: .times para repetir a coleta de dados 3 vezes
3.times do |indice|
print "Digite o #{indice + 1}º número: "
valor = Integer(gets.chomp)
numeros << valor # Adiciona na lista
end
# Ordena e inverte
numeros.sort!.reverse!
puts "\nNúmeros em ordem decrescente:"
# Otimização 2: .each para imprimir, não importa se são 3 ou 100 números
numeros.each do |numero|
puts "-> #{numero}"
end
Aqui, usamos .times para coletar os números dinamicamente, sem precisar criar várias variáveis. Depois, usamos .each para exibir os números ordenados, o que funciona para qualquer quantidade de números na lista.
Média Escolar
Apesar do .each ser preferido em Ruby, o for pode ser usado para iterar (que é passar por cada item) sobre uma lista de notas. Vamos adaptar o exercício de média para calcular a média de uma lista de notas. Essa lista de notas agora será passada pela pessoa e guardada em, um array.
notas = []
puts "Digite as notas dos alunos (digite 'sair' para terminar):"
while true
print "Nota: "
entrada = gets.chomp
break if entrada.downcase == 'sair' # Sai do loop se a pessoa digitar 'sair'
nota = Float(entrada) rescue nil
if nota && nota >= 0 && nota <= 10
notas << nota # Adiciona a nota ao array
else
puts "Nota inválida! Digite um número entre 0 e 10."
end
end
if notas.empty?
puts "Nenhuma nota foi informada."
else
soma = 0.0
# Usando for para iterar sobre as notas
for nota in notas
soma += nota
puts "Adicionando #{nota}, soma atual: #{soma}"
end
media = soma / notas.length
puts "A média das notas é: #{media.round(2)}"
# Verificando aprovação
if media >= 7
puts "Aluno aprovado!"
else
puts "Aluno reprovado! Pois ficou com média abaixo de 7."
end
end
Aqui, usamos um laço while true para permitir que a pessoa digite várias notas até que ela decida sair digitando “sair”. As notas válidas (entre 0 e 10) são armazenadas em um array chamado notas.
Depois, usamos um laço for para iterar sobre cada nota no array, somando-as para calcular a média. Finalmente, verificamos se o aluno foi aprovado ou reprovado com base na média calculada.
Resumo
Neste artigo, aprendemos sobre as estruturas de repetição (ou laços) em Ruby. Elas servem para fazer o computador repetir uma tarefa sem você precisar copiar e colar o mesmo código várias vezes.
Primeiro, vimos os laços que dependem de uma condição:
- O
while: repete o código enquanto a condição for verdadeira. - O
until: repete o código até que a condição fique verdadeira (ou seja, ele roda enquanto a condição ainda é falsa).
Depois, vimos os laços que passam por uma coleção (uma lista de itens como ranges, arrays ou hashes):
- O
for: percorre uma sequência, como um intervalo de números (range) ou uma lista (array). - O
each: é o jeito mais comum no Ruby para percorrer itens de uma coleção (array,hash, etc.). Também vimos oeach_with_index, que mostra a posição (índice) junto com o item. - O
times: repete uma ação um número exato de vezes.
Para fechar, os exercícios mostraram por que laços são tão úteis no dia a dia:
- Programas mais “pacientes”: dá para pedir a mesma informação até a pessoa digitar certo, em vez de o programa encerrar no primeiro erro.
- Trabalhar com vários dados: em vez de usar muitas variáveis soltas, você pode guardar tudo em um
arraye repetir a lógica quantas vezes precisar. - Automatizar tarefas: laços ajudam a repetir passos que seguem um padrão, economizando tempo e deixando o código mais organizado.
Em resumo, as estruturas de repetição servem para resolver problemas sem se repetir código, essas estruturas são muito poderosas e essenciais para qualquer programa. Claro que, nenhuma dessas estruturas é uma bala de prata que resolve todos os problemas, é preciso saber quando e como usar cada uma delas para tirar o máximo proveito.
Além disso, fortalecer nossa lógica de programação é fundamental para escrever condições de parada corretas e eficientes, evitando loops infinitos que podem travar o programa. Por isso de agora em diante, haverá muitos exercícios práticos para fixar esses conceitos.