Ahhhh, controle de fluxo. É aqui que tudo se junta. Ainda que este capítulo seja mais curto e fácil que o capítulo sobre métodos, ele vai abrir um mundo de possibilidades de programação. Após este capítulo, poderemos escrever programas realmente interativos; antes fizemos programas que dizem coisas diferentes dependendo do que você escreve, mas após este capítulo eles farão coisas diferentes, também. Todavia, temos que poder comparar objetos no nosso programa. Precisamos de...
Vamos ser rápidos por aqui para chegar até as ramificações, que é onde as coisas legais começam a acontecer. Para ver se um objeto é maior ou menor que outro, usamos os métodos > e <, assim:
puts 1 > 2 puts 1 < 2
false true
Tudo em ordem. Do mesmo modo, podemos descobrir se um objeto é maior-ou-igual-que (ou menor-ou-igual-que) outro com os métodos >= e <=.
puts 5 >= 5 puts 5 <= 4
true false
Por fim, podemos descobrir se dois objetos são iguais ou não usando == (que significa "estes objetos são iguais?") e != (que significa "estes objetos são diferentes?"). É importante não confundir = com ==. = serve para dizer a uma variável que aponte para um objeto (atribuição), e == é para fazer a pergunta: "Estes dois objetos são iguais?".
puts 1 == 1 puts 2 != 1
true true
E é claro que também podemos comparar strings. Quando strings
são comparadas, leva-se em conta seus
puts 'cachorro' < 'gato'
true
Há um porém: os computadores costumam ordenar letras maiúsculas antes de minúsculas, como se viessem antes (é assim que guardam as letras em fontes, por exemplo: todas as letras maiúsculas primeiro, seguidas das minúsculas). Isso significa que o computador vai pensar que 'Zoológico' vem antes de 'abelha', então se você quiser descobrir qual palavra viria primeiro num dicionário de verdade, use downcase (ou upcase ou capitalize) em ambas as palavras antes de tentar compará-las.
Uma última observação antes de Ramificações: os métodos de comparação não estão nos dando as strings 'true' e 'false'; elas estão nos dando os objetos especiais true e false (claro, true.to_s nos dá 'true', que é como puts imprimiu 'true'). true e false são usados o tempo todo em...
"Ramificação" é um conceito simples, mas poderoso. Na verdade, é tão simples que aposto que nem tenho que explicá-lo; deixa eu mostrar para você:
puts 'Olá, qual é o seu nome?' nome = gets.chomp puts 'Olá, ' + nome + '.' if nome == 'Chris' puts 'Que nome bonito!' end
Olá, qual é o seu nome?
Chris
Olá, Chris.
Que nome bonito!
Mas se colocarmos um nome diferente...
Olá, qual é o seu nome?
Chewbacca
Olá, Chewbacca.
E isso é ramificar. Se o que vem depois de if (N.T.—se) é true, nós executamos o código entre if e end. Se o que vem depois de if é false, não executamos nada. Claro e simples.
Eu indentei o código entre if e end porque acho que fica mais fácil acompanhar as ramificações assim. Quase todos os programadores fazem isso, independente da linguagem em que estejam trabalhando. Pode não parecer muito útil neste exemplo pequeno, mas quando as coisas ficam mais complexas, faz uma baita diferença.
Muitas vezes gostaríamos que um programa fizesse uma coisa se uma expressão for true, e outra se for false. É para isso que serve else:
puts 'Eu sou um vidente. Diga-me seu nome:' nome = gets.chomp if nome == 'Chris' puts 'Vejo coisas maravilhosas no seu futuro.' else puts 'Seu futuro é... Ó, Deus! Olha a hora!' puts 'Eu tenho que ir, mil perdões!' end
Eu sou um vidente. Diga-me seu nome:
Chris
Vejo coisas maravilhosas no seu futuro.
Agora vamos tentar um nome diferente...
Eu sou um vidente. Diga-me seu nome:
Ringo
Seu futuro é... Ó, Deus! Olha a hora!
Eu tenho que ir, mil perdões!
Ramificar é como deparar com uma bifurcação no código: tomamos o caminho para as pessoas com o nome == 'Chris' ou else, tomamos o outro caminho?
E como os galhos de uma árvore, você pode ter ramificações que contêm suas próprias ramificações:
puts 'Olá, e bem-vindo à aula de Português.' puts 'Meu nome é professora Hélia. Seu nome é...?' nome = gets.chomp if nome == nome.capitalize puts 'Por favor, sente-se, ' + nome + '.' else puts nome + '? Você quer dizer ' + nome.capitalize + ', não é?' puts 'Você não sabe nem escrever seu nome??' resposta = gets.chomp if resposta.downcase == 'sim' puts 'Hunf! Vá, sente-se!' else puts 'FORA!!!' end end
Olá, e bem-vindo à aula de Português. Meu nome é professora Hélia. Seu nome é...? chris chris? Você quer dizer Chris, não é? Você não sabe nem escrever seu nome?? sim Hunf! Vá, sente-se!
Está bem, vou capitalizar...
Olá, e bem-vindo à aula de Português.
Meu nome é professora Hélia. Seu nome é...?
Chris
Por favor, sente-se, Chris.
Às vezes pode ficar confuso entender onde colocar os ifs, elses e ends. O que eu faço é escrever o end ao mesmo tempo que escrevo o if. Então enquanto eu estava escrevendo o programa acima, ele estava primeiro assim:
puts 'Olá, e bem-vindo à aula de Português.' puts 'Meu nome é professora Hélia. Seu nome é...?' nome = gets.chomp if nome == nome.capitalize else end
Aí eu preenchi com comentários, coisas no código que o computador irá ignorar:
puts 'Olá, e bem-vindo à aula de Português.' puts 'Meu nome é professora Hélia. Seu nome é...?' nome = gets.chomp if nome == nome.capitalize # Ela é cordial. else # Ela fica brava. end
Qualquer coisa após um # é considerado um comentário (a não ser, é claro, que você esteja em uma string). Depois de preencher com comentários, substituí-os por código funcional. Algumas pessoas gostam de deixá-los no arquivo; particularmente, creio que código bem-escrito fala por si. Eu costumava escrever mais comentários, mas quanto mais "fluente" fico em Ruby, menos faço uso deles. Eles me distraem boa parte do tempo. É uma escolha individual; você vai encontrar o seu estilo (normalmente em constante evolução). Então meu próximo passo ficou assim:
puts 'Olá, e bem-vindo à aula de Português.' puts 'Meu nome é professora Hélia. Seu nome é...?' nome = gets.chomp if nome == nome.capitalize puts 'Por favor, sente-se, ' + nome + '.' else puts nome + '? Você quer dizer ' + nome.capitalize + ', não é?' puts 'Você não sabe nem escrever seu nome??' resposta = gets.chomp if resposta.downcase == 'sim' else end end
Mais uma vez escrevi if, else e end ao mesmo tempo. Realmente me ajuda a saber "onde estou" no código. Também faz com que o trabalho pareça mais fácil porque posso me concentrar em uma parte pequena, como preencher o código entre if e else. Uma outra vantagem de fazê-lo desta maneira é que o computador pode entender o programa em qualquer estágio. Qualquer uma das versões inacabadas do programa que eu lhe mostrei rodariam. Elas não estavam terminadas, mas eram programas funcionais. Desta maneira eu pude testar enquanto escrevia, o que me ajudou a ver como o programa progredia e o que precisava ser melhorado. Quando ele passou em todos os testes, eu soube que estava pronto!
Essas dicas vão ajudá-lo a escrever programas que se ramificam, mas também ajudam com outro tipo central de controle de fluxo:
Você vai querer com alguma freqüência que o computador faça a mesma coisa várias e várias vezes—afinal, é nisso que os computadores, em teoria, são bons.
Quando você manda o seu computador ficar repetindo algo, você também precisa dizê-lo quando parar. Computadores nunca se entediam, então se você não mandar o seu parar, ele não parará. Garantimos que isso não aconteça ao dizermos que ele deve repetir certas partes de um programa while (N.T.—enquanto) uma condição especificada for verdadeira. O funcionamento é bem parecido com o do if:
comando = '' while comando != 'tchau' puts comando comando = gets.chomp end puts 'Volte logo!'
Olá? Olá? Oi! Oi! Muito prazer em conhecê-lo. Muito prazer em conhecê-lo. Ah... que amor! Ah... que amor! tchau Volte logo!
E isso é um loop (você deve ter notado a linha em branco no começo da saída; ela vem do primeiro puts, antes do primeiro gets. Como você modificaria o programa para se livrar dessa primeira linha? Teste! Funcionou exatamente como o programa acima, fora aquela primeira linha em branco?).
Loops, ou repetições, permitem que você faça várias coisas interessantes, como sei que você pode imaginar. Mas também podem causar problemas se você cometer algum erro. E se o computador ficar preso num loop infinito? Se você acha que isso pode ter acontecido, é só segurar a tecla Ctrl e pressionar C.
Antes de começarmos a brincar com loops, vamos aprender algumas coisinhas para facilitar nossa vida.
Vamos dar uma olhada no nosso primeiro programa com ramificações. E se minha esposa chegasse em casa, visse o programa, tentasse usá-lo e ele não dissesse que nome bonito ela tem? Eu não gostaria de magoá-la (ou de dormir no sofá), então vamos reescrevê-lo:
puts 'Olá, qual é o seu nome?' nome = gets.chomp puts 'Olá, ' + nome + '.' if nome == 'Chris' puts 'Que nome bonito!' else if nome == 'Katy' puts 'Que nome bonito!' end end
Olá, qual é o seu nome?
Katy
Olá, Katy.
Que nome bonito!
Bom, funciona... mas não é lá um programa muito bonito. E por quê? A melhor regra que eu aprendi sobre programação foi a regra DRY: Don't Repeat Yourself (N.T.—Não Se Repita). Eu poderia escrever um livro só sobre o quão boa ela é. No nosso caso, repetimos a linha Que nome bonito!. Por que é que isso é um problema? Bem, e se eu cometi um erro de digitação quando eu reescrevi? E se eu quisesse mudar de bonito para gracioso em ambas as linhas? Eu sou preguiçoso, lembra? Basicamente, se eu quero que meu programa faça a mesma coisa quando receber Chris ou Katy, então ele realmente deve fazer a mesma coisa:
puts 'Olá, qual é o seu nome?' nome = gets.chomp puts 'Olá, ' + nome + '.' if (nome == 'Chris' or nome == 'Katy') puts 'Que nome bonito!' end
Olá, qual é o seu nome?
Katy
Olá, Katy.
Que nome bonito!
Muito melhor. Para que funcionasse, usei or. Os outros operadores lógicos são and e not. É sempre bom usar parênteses ao trabalhar com eles. Vamos ver como funcionam:
euSouChris = true euSouRoxo = false euAmoComida = true euComoPedras = false puts (euSouChris and euAmoComida) puts (euAmoComida and euComoPedras) puts (euSouRoxo and euAmoComida) puts (euSouRoxo and euComoPedras) puts puts (euSouChris or euAmoComida) puts (euAmoComida or euComoPedras) puts (euSouRoxo or euAmoComida) puts (euSouRoxo or euComoPedras) puts puts (not euSouRoxo) puts (not euSouChris)
true false false false true true true false true false
O único deles que pode enganá-lo é or (N.T.—ou). Em português, usa-se "ou" para dizer "um ou outro, mas não os dois". Por exemplo, sua mãe pode lhe dizer: "Para sobremesa você pode escolher torta ou bolo". Ela não deu a opção de escolher os dois! Um computador, por outro lado, entende or como "ou um ou outro, ou os dois" (outro jeito de colocar é "ao menos um destes é verdadeiro"). É por isso que computadores são mais legais que mães.
• "Um elefante incomoda muita gente..." Escreva um programa que imprima a letra para o clássico das viagens de carro, com um limite de 100 elefantes.
• Escreva um programa Velha Surda. O que quer que
você diga à velha (o que quer que você digite), ela tem
que responder com QUE?! FALA MAIS ALTO!, a não
ser que você grite (digite tudo em maiúsculas). Se você
gritar, ela pode lhe ouvir (ou ao menos pensa que pode), e
sempre responde NÃO, NÃO DESDE 1938! Para fazer seu
programa ser realmente verossímil, faça a velha gritar
um número diferente a cada vez; talvez qualquer ano aleatório
entre 1930 e 1950 (a última parte é opcional, e ficaria muito
mais fácil se você lesse a seção sobre o gerador de números
randômicos do Ruby no capítulo sobre
métodos). Você não pode parar
de falar com a velha enquanto não gritar TCHAU.
Dica: Não esqueça do chomp
! 'TCHAU' com um enter não é a mesma coisa que
'TCHAU' sem!
Dica 2: Tente pensar em que partes do programa
as coisas acontecem repetidamente. Todas elas devem estar no seu
loop while.
• Melhore o seu programa Velha Surda: e se a velha não quiser que você vá embora? Quando você gritar TCHAU, ela pode fingir que não lhe ouve. Mude seu programa anterior para que você tenha que gritar TCHAU três vezes em seqüência. Teste bem o seu programa: se você gritar TCHAU três vezes, mas não em seqüência, você tem que continuar falando com a velha.
• Anos bissextos. Escreva um programa que pergunte um ano inicial e um ano final, e imprima com puts todos os anos bissextos entre eles (e os incluindo, se eles também forem bissextos). Anos bissextos são sempre divisíveis por quatro (como 1984 e 2004). Contudo, anos divisíveis por 100 não são bissextos (como 1800 e 1900) a não ser que sejam divisíveis por 400 (como 1600 e 2000, que foram de fato anos bissextos). (Sim, é bem confuso, mas não tão confuso como ter dezembro no meio do inverno, que é o que aconteceria no fim).
Quando você terminá-las, descanse um pouco! Você já aprendeu muitas coisas. Parabéns. Você está surpreso com a quantidade de coisas que se pode mandar o computador fazer? Mais alguns capítulos e você vai poder programar praticamente tudo. Sério mesmo! Veja só tudo que você pode fazer que não podia antes de aprender sobre loops e ramificações.
Agora vamos aprender sobre um novo tipo de objeto, que controla listas de outros objetos: arrays.
© 2003-2015 Chris Pine