[Lua] Aprendendo a programar |
15 | ||
Este tópico junta uma série de tutoriais divididos em parte que têm como objetivo iniciar um usuário na programação, exclusivamente na linguagem Lua. Índice
1.2. O que é um código/programa? 1.3. O que é depuração? 1.4. Depurando seu código 1.5. Seu primeiro programa Parte 2 — Variáveis, expressões e declarações
2.2. Variáveis 2.3. Nomes de variáveis e palavras-chave 2.4. Declarações 2.5. Validando expressões 2.6. Operadores e operandos 2.7. Comentários Parte 3 — Funções
3.3. Parâmetros e argumentos 3.4. Composição Parte 4 — Condicionais
4.2. Operadores lógicos 4.3. Execução condicional 4.4. Execução alternativa 4.5. Condicionais acorrentadas 4.6. Condicionais aninhados Parte 5 — Funções frutíferas
5.2. Desenvolvimento do programa 5.3. Composição 5.4. Funções booleanas 5.5. O tipo function 5.6. Strings multi-linha Parte 6 — Iteração
6.2. Atualizando variáveis 6.3. A declaração while 6.4. Encapsulamento e generalização Tópico baseado em "Learning with python": http://openbookproject.net/thinkcs/python/english2e/ch01.html Dernière modification le 1518272640000 |
7 | ||
Seção 1 (Seção 1) Aprendendo a programar Uma das habilidades essenciais na hora de criar um código é a resolução de problemas, na qual requer que você pense de maneira criativa em soluções que se expressem de forma clara e objetiva. Aprender a programar é uma ótima forma de praticar e aperfeiçoar essa habilidade. (Seção 1.1) O que é a linguagem lua? Lua é uma linguagem de programação poderosa, eficiente e leve, projetada para estender aplicações, é inteiramente projetada, implementada e desenvolvida no Brasil, por uma equipe na PUC-Rio (Pontifícia Universidade Católica do Rio de Janeiro). Lua nasceu e cresceu no Tecgraf, o então Grupo de Tecnologia em Computação Gráfica da PUC-Rio. Atualmente, Lua é desenvolvida no laboratório LabLua do Departamento de Informática da PUC-Rio. - Lua.org Como qualquer outra linguagem de programação, lua serve como uma ponte entre você e o computador permitindo a comunicação e a troca de comandos, podemos dizer que a Linguagem Lua, como outras, é uma especie de tradutor para uma língua que computadores entendem. (Seção 1.2) O que é um código/programa? Um código é uma sequencia de instruções que especifica como fazer uma computação. Pode ser algo matemático como uma soma ou resolução de uma equação, ou até mesmo a procura e a substituição de um texto em um arquivo. Pode ser bem complexo e detalhado, mas as intruções básicas são sempre as mesmas: Input
Output
Execução condicional
Repetição
(Seção 1.3) O que é depuração? Programar é um processo complexo, e por ser feito por humanos, quase sempre erros acontecem. Por uma razão ou outra, erros de programação são chamados de bugs e o processo de identificação e correção de bugs é chamado de depuração. Três tipos de erros podem acontecer em um código: erros de sintáxe, erros de execução e erros de semântica, conseguir identificar o tipo de erro ocorrido acelera a sua depuração. (Seção 1.3.1) Erros de sintáxe Lua pode apenas executar um código caso ele esteja sintaticamente correto, caso o contrário, o processo é abortado e uma mensagem de erro é retornada. Sintáxe como no português ou inglês, se refere à estrutura e as regras daquela estrutura em uma linguagem. Por exemplo, em português uma frase precisa iniciar com uma letra maiúscula e terminar com um ponto final. Para a maioria dos nós leitores, essa regra sintática pode ser ignorada por não ser um problema significante, mas para o Lua e qualquer outra linguagem de programação, erros de sintáxe não são aceitáveis e vão impedir você de rodar seu código. Então é importante memorizar essas estruturas enquanto você aprende a programar. (Seção 1.3.2) Erros de execução Esse tipo de erro é chamado assim por não aparecer até que você inicie seu código. São conhecidos também como exceções pois eles indicam que algo excepcional (e ruim) aconteceu, eles são difíceis de acontecer em códigos simples como os que estaremos discutindo nas próximas seções. (Seção 1.3.3) Erros de semântica O último tipo de erro é o de semântica. Se houver um erro semântico em seu programa, ele será executado com êxito, no sentido de que o computador não irá gerar quaisquer mensagens de erro, mas ele não vai fazer a coisa certa. Vai fazer outra coisa, especificamente, ele vai fazer o que você disse pra ele fazer. O problema é que o código que você escreveu não é o programa que você queria escrever. O significado do código (sua semântica) está errado. Identificar erros semânticos pode ser complicado porque exige que você trabalhe para trás, olhando para o output do programa e tentando descobrir o que está fazendo. (Seção 1.4) Depurando seu código Uma das habilidades mais importantes que você vai adquirir é a depuração. Embora possa ser frustrante, a depuração é uma das partes mais desafiadoras e interessantes da programação. Depuração é como o trabalho de detetive, você é confrontado com pistas, e você tem que inferir os processos e eventos que levaram aos resultados que você vê. (Seção 1.5) Seu primeiro programa Tradicionalmente o primeiro código escrito em uma nova linguagem é chamado Hello, World! porque tudo o que faz é mostrar as palavras Hello World. Na linguagem Lua é mais ou menos assim: Code Lua 1 print('Hello, World!') Este é um exemplo de uma declaração de print, que na verdade não imprime nada, apenas exibe um valor na tela. Neste caso, o resultado são as palavras: Hello, World! As aspas no código marcam o início e o fim do valor que você quer mostrar, eles não irão aparecer no resultado. (Seção 1) Exercícios 1. Digite /lua e insira o código a seguir: Code Lua 1 print(2 + 2) O resultado esperado é 4, já que a expressão dada acima é a de adição, tente mudar o + por *, o que aconteceu agora? Experimente utilizar outros operadores, como - para subtração ou / para divisão. Como você pode perceber, neste caso não utilizamos aspas no print, pois números não precisam delas, estarei explicando isso mais a frente. 2. Agora tente introduzir o código abaixo: Code Lua 1 print(2 2) Não houve sucesso pois o lua não consegue validar a expressão. Mesmo o retorno nesse caso não explicando o erro (')' expected), ele se trata de um problema de sintáxe. Resolva ele e rode o código novamente. Resolução Você pode resolver o erro adicionando um dos operadores citados acima entre os dois números, tornando a expressão valida. Dernière modification le 1515608640000 |
7 | |||||||||||||||||||||||
Seção 2 (Seção 2) Variáveis, expressões e declarações (Seção 2.1) Valores e tipos de dados Um valor é uma das coisas fundamentais - como uma letra ou um número - que um programa manipula. Os valores que vimos até então foram 4, (O resultado das operação matemática 2+2) e Hello, World!. Esses dois valores fazem parte de tipos diferentes de dados: 4 é do tipo number, que representa todos os números e Hello, World!, uma string, essa por vez representa uma sequência de caracteres. Se você não consegue identificar o tipo de um valor, o Lua pode facilmente identificar pra você: Code Lua 1 2 3 4 5 print(type(2)) E valores como "4"? Eles são números mas estão entre aspas como strings: Code Lua 1 2 print(type('4')) Strings na linguagem Lua são delimitadas utilizando aspas (' ou "): Code Lua 1 2 3 4 print(type('Isso é uma string')) Aspas duplas (") podem conter aspas únicas (') dentro, e vice-versa. Quando você estiver digitando um número bem grande, talvez você queira utilizar vírgulas entre grupos de três digitos, como exemplo 1,000,000. Este não é um número valido na linguagem Lua, mas é uma estrutura correta: Code Lua 1 2 print(1,000,000) Bem, isso não é o que esperávamos! Lua interpreta 1,000,000 como uma lista de três itens a serem mostrados. Então lembre-se de não colocar vírgulas em seus números inteiros. (Seção 2.2) Variáveis Uma das características mais poderosas de uma linguagem de programação é a capacidade de manipular variáveis. Uma variável é um nome que se refere a um valor. Utilizamos a declaração de atribuição para criar uma nova variável e atribuir ela um valor: Code Lua 1 2 3 local dia = 'Segunda-feira' Neste exemplo nós criamos três variáveis, a primeira se chama dia e armazena o valor Segunda-feira, uma string. A segunda variável dá o valor 12, um número, para hora e pi recebe o número decimal 3.14. O operador de atribuição(=), não deve ser confundido com um sinal de igual (mesmo que ele utilize o mesmo caractere). Operadores de atribuição vinculam um nome, no lado esquerdo do operador, com um valor no lado direito. É por isso que você vai ter um erro se você rodar o seguinte código: Code Lua 1 local 12 = hora A declaração print também funciona com as variáveis: Code Lua 1 2 3 4 5 6 7 local dia = 'Segunda-feira' Variáveis também possuem um tipo e podemos utilizar type para saber qual: Code Lua 1 2 3 4 5 6 7 local dia = 'Segunda-feira' (Seção 2.3) Nomes de variáveis e palavras-chave Geralmente escolhemos nomes para as variáveis que possuem um significado - comummente elas apontam aonde a variável é usada. Nomes de variáveis não possuem número mínimo e nem máximo de caracteres, elas podem possuir letras e números, mas sempre começar com uma letra. Mesmo que seja ok utilizar letras maiúsculas no nome de uma variável, não é obrigátorio. Caso você decida fazer, lembre-se que Dia e dia são variáveis diferentes. O caractere _ também pode ser utilizado em nomes de váriavel, comumente entre duas palavras, como em dia_do_mes. Utilizar um nome inválido de na hora de declarar uma variável irá retornar um erro de sintáxe: Code Lua 1 2 3 4 5 6 local 5dia = 'sexta' 5dia é um nome inválido pois começa com um número, $dia também é inválido por utilizar um simbolo não aceito. Mas e function? Acontece que function é uma das palavras-chave da linguagem Lua. Palavras-chave definem as regras e a estrutura de uma linguagem e não podem ser usadas como nomes de variáveis.
Se o Lua reclamar sobre um de seus nomes de variáveis e você não sabe por que, veja se ele está nesta lista. (Seção 2.4) Declarações Uma declaração é uma instrução que o Lua pode executar, até agora nós vimos dois tipos de declarações: print e atribuição. Quando você digita uma declaração na linha de comando, lua executa ela e exibe o resultado, se houver um. O resultado de uma declação print é um valor. As declarações de atribuição não produzem resultado. Por exemplo o código abaixo: Code Lua 1 2 3 4 5 print(1) Novamente, a declaração de atribuição não produz nenhuma saída. (Seção 2.5) Validando expressões Uma expressão é uma combinação de valores, variáveis e operadores. Se você digitar uma expressão, o lua o avaliará e exibirá o resultado: Code Lua 1 2 print(1 + 1) A avaliação de uma expressão produz um valor, razão pela qual as expressões podem aparecer no lado direito das declarações de atribuição. Um valor por si só é uma expressão simples, ou seja, é uma variável. Code Lua 1 2 3 local x = 1 + 1 (Seção 2.6) Operadores e operandos Os operadores são símbolos especiais que representam cálculos como adição e multiplicação. Os valores que o operador usa são chamados operandos. A seguir estão todas as expressões legais do Lua cujo significado é mais ou menos claro: Code Lua 1 2 3 4 5 6 20+32 Os símbolos + - e /, e o uso de parênteses, significam em Lua o que eles significam em matemática. O asterisco (*) é simbolo de multiplicação e ^ é o simbolo de exponenciação. Quando um nome de variável aparece no lugar de um operando, ele é substituído por seu valor antes que a operação seja executada. (Seção 2.6.2) Ordem de operações Quando mais de um operador aparece em uma expressão, a ordem de avaliação depende das regras de precedência. Lua segue as mesmas regras de precedência para seus operadores matemáticos que a matemática faz. O acrônimo PEMDAS é uma maneira útil de lembrar a ordem das operações:
2. Exponenciação tem a próxima maior precedência, então 2 ^ 1 + 1 é 3 e não 4, e 3 * 1 ^ 3 é 3 e não 27. 3. Multiplicação e Divisão têm a mesma precedência, que é maior do que a Adição e Subtração, que também têm a mesma precedência. Então 2 * 3 - 1 rende 5 em vez de 4, e 2 / 3 - 1 é -1, não 1 (Lembre-se que na divisão de inteiros, 2/3 = 0). Lembre que não é possível utilizar essas operações em strings, a não ser que elas apenas contenham números dentro. Mas é possível utilizar o operador .. para unir duas strings: Code Lua 1 2 3 4 5 6 7 8 9 10 11 12 13 14 local parte1 = 'Olá' (Seção 2.7) Comentários Como os códigos vão ficando maiores e maiores, eles se tornam mais difíceis de ler. Por esta razão, é uma boa idéia adicionar comentários aos seus códigos para explicar o que essa parte está fazendo. Essas anotações são chamadas de comentários, e elas são marcadas com o símbolo --: Code Lua 1 2 -- Calcula a porcentagem da hora que já passou Você também pode adicionar comentários no fim de uma linha: Code Lua 1 local porcentagem = (minuto * 100) / 60 -- Calcula a porcentagem da hora que já passou Tudo do -- até o final da linha é ignorado - ele não tem efeito sobre o código. A mensagem destina-se para o programador ou para futuros programadores que possam utilizar este código. Neste caso, ele lembra o leitor sobre o comportamento da divisão. (Seção 2) Exercícios 1. Pegue a frase Programar lua é legal, armazene cada palavra numa variável separada e então utilize o print para mostrar ela em uma linha. Resolução Code Lua 1 2 3 4 5 local a = 'Programar' 2. Adicione parênteses à expressão 6 * 1 - 2 para alterar seu valor de 4 para -6. Resolução Code Lua 1 print(6 * (1 - 2)) 3. Faça com que o código print(hora + 1) retorne o valor 13. Resolução Code Lua 1 2 local hora = 12 Dernière modification le 1515608580000 |
7 | ||
Seção 3 (Seção 3) Funções No contexto de programação, uma função é uma sequência nomeada de instruções que executa uma operação desejada. Essa operação é especificada em uma declaração de função. Em Lua, a sintáxe para uma função é: Code Lua 1 2 3 function nome(parametro_1, parametro_2) Você pode dar os nomes que desejar para as funções criadas, desde que não seja uma palavra-chave. A lista de parâmetros especifica quais informações, se houver, você tem que fornecer para usar a nova função. Pode haver qualquer número de declarações dentro da função, mas elas precisam estar dentro do end da função. As declarações de função são as primeiras de várias declarações compostas que veremos, todas com o mesmo padrão: 1. Um cabeçalho, que começa com uma palavra-chave; 2. Um corpo constituído por uma ou mais instruções; 4. A palavra-chave end, delimitando a declaração. Code Lua 1 2 3 function iniciar() Essa função se chama iniciar, os parênteses vazios indicam que ele não tem parâmetros. Seu corpo contém apenas uma única instrução, que produz um print com Olá mundo!. Definir uma nova função não faz a função executar. Para fazer isso, precisamos de uma chamada de função. Chamadas de função contêm o nome da função que está sendo executada seguido por uma lista de valores, chamado argumentos, que são atribuídos aos parâmetros na declaração de função. Nossos primeiros exemplos têm uma lista de parâmetros vazia, portanto, as chamadas de função não aceitam argumentos. Observe, no entanto, que os parênteses são exigidos na chamada de função: Code Lua 1 2 3 4 5 6 function iniciar() E se eu quiser repetir Olá mundo! três vezes? Code Lua 1 2 3 4 5 6 7 8 9 10 function iniciar() Você pode até declarar uma função diferente pra repetir a função iniciar! Code Lua 1 2 3 4 5 6 7 8 9 10 11 function iniciar() Você deve observar algumas coisas sobre este código:
2. Você pode ter uma função chamando outra função, como é o caso acima
2. Criar uma nova função pode tornar um programa menor, eliminando código repetitivo. Por exemplo, uma maneira curta de mostrar nove linhas consecutivas é chamar repetir três vezes. Como você pode ter imaginado, é preciso criar uma função antes de executá-la. Em outras palavras, a declaração de função deve ser executada antes da primeira chamada daquela função. No transformice, as funções descritas na documentação Lua são chamadas automaticamente pelo servidor, por exemplo eventNewGame irá ser chamada no código sempre que um novo mapa iniciar, então você não precisa utilizar eventNewGame() para iniciar a função. (Seção 3.2) Fluxo de execução Para garantir que uma função seja definida antes de seu primeiro uso, você tem que saber a ordem em que as instruções são executadas, que é chamado de fluxo de execução. A execução sempre começa na primeira declaração do programa. As instruções são executadas uma de cada vez, em ordem de cima para baixo. Declarações de função não alteram o fluxo de execução do programa, mas lembre-se de que o código dentro da função não é executado até que a função seja chamada. Embora não seja comum, você pode definir uma função dentro de outra. Nesse caso, a definição interna não é executada até que a função externa seja chamada. Chamadas de função são como um desvio no fluxo de execução. Em vez de ir para a próxima linha, o fluxo salta para a primeira linha da função chamada, executa todas as declarações lá e, em seguida, volta para continuar de onde ele saiu. Então qual é a moral disso tudo? Quando você lê um programa, não leia de cima para baixo. Em vez disso, siga o fluxo de execução. (Seção 3.3) Parâmetros e argumentos A maioria das funções requerem argumentos, valores que controlam como a função faz seu trabalho. Por exemplo, se você quiser encontrar o valor absoluto de um número, você tem que indicar qual é o número. Lua tem uma função embutida para calcular o valor absoluto: Code Lua 1 2 3 4 print(math.abs(10)) Neste exemplo, os argumentos para a função math.abs são 10 e -10. Algumas funções usam mais de um argumento. Por exemplo, a função interna math.pow precisa de dois argumentos, a base e o expoente. Dentro da função, os valores que são passados são atribuídos a variáveis chamadas parâmetros: Code Lua 1 2 3 4 print(math.pow(2, 3)) Outra função interna que usa mais de um argumento é math.max: Code Lua 1 2 3 4 5 6 print(math.max(2, 3)) math.max pode ser enviado qualquer número de argumentos, separados por vírgulas, e retornará o valor máximo enviado. Os argumentos podem ser valores simples ou expressões. No último exemplo, 100 é retornado pois 5*20 (100) é maior que 10, que é maior que 3, que é maior que 2. Aqui está um exemplo de uma função que tem um parâmetro: Code Lua 1 2 3 function mostrar(mensagem) Essa função utiliza um único argumento atribuido ao parâmetro mensagem. O valor do parâmetro (neste ponto, não temos idéia do que será) vai ser mostrado pelo print. Em geral, você vai querer escolher um nome para seus parâmetros que descreve seu uso na função. Podemos utilizar o código a seguir para testar a função criada: Code Lua 1 2 3 4 5 6 function mostrar(mensagem) (Seção 3.4) Composição Assim como com funções matemáticas, as funções do Lua podem ser compostas, o que significa que você usa o resultado de uma função como entrada para outra. Code Lua 1 2 3 4 5 6 function adicionar_dois(numero) Neste exemplo, math.abs retorna 5, que se torna o argumento para adicionar_dois. Também podemos utilizar uma variável como argumento: Code Lua 1 2 3 4 5 6 7 function adicionar_dois(numero) Note algo muito importante aqui. O nome da variável que passamos como um argumento (negativo) não tem nada a ver com o nome do parâmetro (numero). Novamente, é como se numero = negativo seja declarado quando a função adicionar_dois seja chamada. Não importa o que o valor foi nomeado no chamador, em adicionar_dois seu nome é numero. Uma variável que foi definida utilizando local dentro de uma função não irá existir fora dela, caso você queira definir uma variável global, basta remover o local: Code Lua 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 function criar_var() Mas diferente de variáveis, parâmetros de uma função não existem fora dela. (Seção 3) Exercícios 1. O código abaixo possui um erro crítico no fluxo de execução, corrija-o. Code Lua 1 2 3 4 honk() Resolução A função honk está sendo chamada antes de ser declarada. Code Lua 1 2 3 4 5 function honk() 2. Crie uma função que some dois números, sempre mostrando um número absoluto como resultado: Code Lua 1 2 SEU CODIGO AQUI O resultado esperado deve ser 6. Resolução A aproximação mais simples é: Code Lua 1 2 3 4 function somar(a, b) 3. Crie uma função que defina a variável beep como global com o valor robot. Depois utilize print para mostrar ela fora da função. Resolução Code Lua 1 2 3 4 5 6 function definir() Dernière modification le 1515608520000 |
6 | ||
Seção 4 (Seção 4) Condicionais (Seção 4.1) Valores e expressões booleanas O tipo Lua utilizado para armazenar valores true e false é chamado boolean, nomeado após o matemático britânico, George Boole. George Boole criou a álgebra booleana, que é a base de toda a aritmética computacional moderna. Existem dois tipos de valores booleanos: true e false, note que ambos os valores devem estar em minúsculas, visto que TRUE ou True não são valores booleanos. Code Lua 1 2 3 4 5 6 7 8 print(type(true)) Uma expressão booleana é uma expressão que é avaliada como um valor booleano. O operador == compara dois valores e produz um valor booleano: Code Lua 1 2 3 4 5 print(10 == 10) Na primeira declaração, os dois operandos são iguais, portanto, a expressão é avaliada como true (verdadeiro); na segunda declaração, 10 não é igual a 15, então nós temos false (falso) como retorno. O operador == é um dos operadores de comparação, estes são todos os operadores da linguagem Lua:
x > y - x é maior que y; x < y - x é menor que y; x >= y - x é maior que ou igual a y; x <= y - x é menor que ou igual a y. (Seção 4.2) Operadores lógicos Há três operadores lógicos: and, or e not. A semântica (significado) desses operadores é semelhante ao seu significado em inglês. Por exemplo, x > 0 and x < 10 é verdadeiro somente se x for maior que 0 e menor que 10. Finalmente, o operador not nega uma expressão booleana, portanto, not (x > y) é verdadeiro se (x > y) for falso, ou seja, se x for menor ou igual a y. (Seção 4.3) Execução condicional A fim de escrever programas úteis, quase sempre precisamos da capacidade de verificar as condições e alterar o comportamento do código em conformidade. Declarações condicionais nos dão essa habilidade. A forma mais simples é a declaração if: Code Lua 1 2 3 if x > 0 then A expressão booleana após a o if é chamada de condição. Se for true, em seguida, o código é executado até o seu end. Se não, nada acontece. A sintaxe para uma declaração if se parece com isso: Code Lua 1 2 3 if EXPRESSÃO_BOOLEANA then Como com a definição de função do último capítulo e outras declarações compostas, a instrução if consiste em um cabeçalho, um corpo e a palavra-chave end. O cabeçalho começa com a palavra-chave if seguido por uma expressão booleana e termina com then. Cada uma das instruções dentro do corpo são executadas em ordem se a expressão booleana for avaliada como true. O código inteiro dentro do corpo é ignorado se a expressão booleana for avaliada como false. (Seção 4.4) Execução alternativa Uma segunda forma da declaração if é a execução alternativa, na qual há duas possibilidades e a condição determina qual delas é executada. A sintaxe se parece com isso: Code Lua 1 2 3 4 5 if (x < 0) then Se X for um número negativo (-1 por exemplo), a primeira condição if será ativada. Se X for um número positivo ou for 0, a primeira condição será false e a segunda condição irá ser checada, assim até que uma das condições seja verdadeira ou não exista nenhuma mais para checar. Como a condição deve ser verdadeira ou falsa, exatamente uma das alternativas será executada. As alternativas são chamadas de ramificações, porque elas são ramificações no fluxo de execução. Code Lua 1 2 3 4 5 6 7 function checar_numero(x) Para qualquer valor de x, checar_numero exibe uma mensagem apropriada. Quando você chamá-lo, você pode fornecer qualquer expressão inteira como um argumento. Code Lua 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 function checar_numero(x) (Seção 4.5) Condicionais acorrentadas Às vezes há mais de duas possibilidades e precisamos de mais de dois ramos. Uma maneira de expressar uma computação como essa é uma condicional encadeada: Code Lua 1 2 3 4 5 6 7 if (x > y) then elseif é uma abreviação de else if e permite que duas condições sejam checadas de uma vez. Mais uma vez, exatamente um ramo será executado. Não há limite do número de instruções elseif, mas apenas uma única (e opcional) instrução [n]else[/n] é permitida e deve ser a última ramificação na instrução. Cada condição é checada em ordem. Se a primeira é false, a próxima é verificada e assim por diante. Se uma delas for true, a ramificação correspondente é executada e a instrução termina. Mesmo que mais de uma condição seja verdadeira, somente a primeira ramificação verdadeira é executada. (Seção 4.6) Condicionais aninhados Uma condicional também pode ser aninhada dentro de outra. Poderíamos ter escrito o exemplo acima assim: Code Lua 1 2 3 4 5 6 7 8 9 if (x > y) then A condicional externa contém duas ramificações. A primeira ramificação contém uma declaração de saída simples. A segunda ramificação contém outra instrução if, que tem duas ramificações próprias. Essas duas ramificações são ambas as declarações de saída, embora poderiam ter sido declarações condicionais também. Embora o recuo das declarações torna a estrutura aparente, condicionais aninhadas tornam-se difíceis de ler muito rapidamente. Em geral, é uma boa idéia evitá-las quando você pode. Operadores lógicos geralmente fornecem uma maneira de simplificar aninhadas instruções condicionais. Por exemplo, podemos reescrever o código a seguir usando um único condicional: Code Lua 1 2 3 4 5 if (0 < x) then A instrução print é executada somente se ambos os condicionais forem true, então nós podemos usar o operador and: Code Lua 1 2 3 if (0 < x and x < 10) then (Seção 4.7) Declaração de retorno A instrução return permite que você encerre a execução de uma função antes de chegar ao final. Uma razão para usá-lo é se você detectar uma condição de erro: Code Lua 1 2 3 4 5 6 7 8 function raiz_quadrada(x) A função raiz_quadrada tem um parâmetro chamado x. A primeira coisa que ela faz é verificar se x é menor ou igual a 0, caso em que ele exibe uma mensagem de erro e, em seguida, usa return para sair da função. O fluxo de execução retorna imediatamente para o chamador e as linhas restantes da função não são executadas. (Seção 4) Exercícios 1. Adicione o código abaixo dentro de uma função chamada comparar: Code Lua 1 2 3 4 5 6 7 if (x > y) then Chame comparar três vezes: cada uma onde o primeiro argumento é menor que, maior que e igual ao segundo argumento. Resolução Code Lua 1 2 3 4 5 6 7 8 9 10 11 12 13 function comparar(x, y) Os valores em comparar podem ser mudados para qualquer número, desde que produzam o mesmo resultado. 2. Qual resultado obtido no código abaixo? Code Lua 1 2 3 4 5 if ('Ni!') then Modifique o código fazendo Pare! Chega disso! aparecer. Resolução Podemos facilmente editar o código, adicionando o operador not Code Lua 1 2 3 4 5 if (not('Ni!')) then Dernière modification le 1515608580000 |
7 | ||
Seção 5 (Seção 5) Funções frutíferas (Seção 5.1) Valor de retorno As funções internas que usamos, como math.abs, math.pow e math.max, produziram resultados. Chamar cada uma dessas funções gera um valor, que normalmente atribuímos a uma variável ou usamos como parte de uma expressão. Code Lua 1 2 local maior = math.max(4, 7, 11, 3) Mas até agora, nenhuma das funções que escrevemos retornou um valor. Neste seção, vamos escrever funções que retornem valores, que iremos chamar de funções frutíferas. O primeiro exemplo é calcular_area, que retorna a área de um círculo com o raio determinado: Code Lua 1 2 3 4 function calcular_area(raio) Vimos a declaração de retorno antes, mas em uma função frutífera a declaração return inclui um valor de retorno. Essa instrução significa: retornar imediatamente a partir dessa função e usar a seguinte expressão como um valor de retorno. A expressão fornecida pode ser arbitrariamente complicada, então poderiamos ter escrito esta função de forma mais concisa: Code Lua 1 2 3 function calcular_area(raio) Por outro lado, variáveis temporárias como valor geralmente tornam a depuração mais fácil. Às vezes é útil ter várias declarações de retorno, uma em cada ramificação de uma condicional: Code Lua 1 2 3 4 5 6 7 function numero_absoluto(x) Uma vez que estas declarações de retorno estão em uma condicional alternativa, apenas uma será executada. Assim que uma é executada, a função termina sem executar quaisquer instruções subsequentes. Uma outra maneira de escrever a função acima é deixar para fora o outro e apenas seguir a condição se pela segunda indicação do retorno: Code Lua 1 2 3 4 5 6 function numero_absoluto(x) Qualquer código que aparece após uma instrução return, ou qualquer outro lugar que o fluxo de execução nunca pode alcançar, é chamado de código morto. Em uma função frutífera, é uma boa idéia garantir que cada caminho possível através do programa atinge uma declaração de retorno. A seguinte versão da função numero_absoluto não consegue fazer isso: Code Lua 1 2 3 4 5 6 7 function numero_absoluto(x) Esta versão não está correta porque se x acontecer de ser 0, nenhuma condição é verdadeira e a função termina sem uma instrução return. Nesse caso, o valor de retorno é um valor especial chamado nil: Code Lua 1 2 3 4 5 6 7 8 9 10 function numero_absoluto(x) (Seção 5.2) Desenvolvimento do programa Neste ponto, você deve ser capaz de olhar para as funções completas e dizer o que eles fazem. Também, se você tem feito os exercícios, você escreveu algumas funções pequenas. À medida que você escreve funções maiores, você pode começar a ter mais dificuldade, especialmente com erros de tempo de execução e semântica. Para lidar com códigos cada vez mais complexos, vamos sugerir uma técnica chamada desenvolvimento incremental. O objetivo do desenvolvimento incremental é evitar longas sessões de depuração, adicionando e testando apenas uma pequena quantidade de código por vez. Como um exemplo, suponha que você deseja localizar a distância entre dois pontos, dado pelas coordenadas (x1, y1) e (x2, Y2). Pelo teorema de Pitágoras, a distância é:
Neste caso, os dois pontos são as entradas, que podemos representar usando quatro parâmetros. O valor de retorno é a distância, que é um valor de ponto flutuante. Já podemos escrever um esboço da função: Code Lua 1 2 3 function distance(x1, y1, x2, y2) Obviamente, esta versão da função não computa distâncias, ela sempre retorna zero. Mas é sintaticamente correta, o que significa que podemos testá-la antes de torná-la mais complicada. Code Lua 1 2 3 4 5 6 function distance(x1, y1, x2, y2) Esses valores foram escolhidos para que a distância horizontal seja igual a 3 e a distância vertical seja igual a 4, dessa forma, o resultado é 5 (a hipotenusa de um triângulo 3-4-5). Ao testar uma função, é útil saber a resposta certa. Neste ponto, temos confirmado que a função é sintaticamente correta, e podemos começar a adicionar linhas de código. Após cada mudança incremental, testamos novamente a função. Se ocorrer um erro em qualquer ponto, saberemos onde ele deve estar — na última linha que adicionamos. A primeira etapa lógica na computação é encontrar os valores de x2-x1 e y2-y1. Vamos armazenar esses valores em variáveis temporárias chamadas dx e dy e depois utilizar print. Code Lua 1 2 3 4 5 6 7 8 9 function distance(x1, y1, x2, y2) Se a função estiver funcionando, as saídas devem ser 3 e 4. Se assim for, sabemos que a função está obtendo os parâmetros certos e executando o primeiro cálculo corretamente. Se não, há apenas algumas linhas para verificar. Em seguida, calculamos a soma dos quadrados de dx e dy: Code Lua 1 2 3 4 5 6 7 8 9 function distance(x1, y1, x2, y2) Novamente, vamos executar o programa nesta fase e verificar a saída (que deve ser 25). Finalmente, usando o expoente fracionário 0.5 para encontrar a raiz quadrada, nós calculamos e retornamos o resultado: Code Lua 1 2 3 4 5 6 7 8 9 function distance(x1, y1, x2, y2) Quando você começa, você deve adicionar apenas uma linha ou dois de código por vez. Como você ganha mais experiência, você pode escrever e depurar pedaços maiores de códigos. De qualquer forma, o processo de desenvolvimento incremental pode economizar muito tempo de depuração. Os principais aspectos do processo são:
2. Use variáveis temporárias para conter valores intermediários para que você possa verificar eles. 3. Uma vez que o programa está funcionando, você pode remover alguns dos "andaimes" ou consolidar várias declarações em expressões compostas, mas apenas se ele não faz o código difícil de ler. Como é de se esperar, você pode chamar uma função de dentro de outra. Essa habilidade é chamada de composição. Como exemplo, vamos escrever uma função que utiliza dois pontos, o centro do círculo e um ponto no perímetro, e calcula a área do círculo. Suponha que o ponto central é armazenado nas variáveis cx e cy, e o ponto de perímetro está em px e py. O primeiro passo é encontrar o raio do círculo, que é a distância entre os dois pontos. Felizmente, acabamos de escrever uma função, distância, que faz exatamente isso, então agora tudo o que temos a fazer é usá-la: Code Lua 1 local raio = distance(cx, cy, px, py) A segunda etapa é encontrar a área de um círculo com esse raio e retorná-la. Mais uma vez usaremos uma de nossas funções anteriores: Code Lua 1 2 local resultado = calcular_area(raio) Colocando tudo isso em uma função, nós temos: Code Lua 1 2 3 4 5 function calcular_area2(cx, cy, px, py) Chamamos essa função de calcular_area2 para distingui-lo da função calcular_area definida anteriormente. Só pode haver uma função com um determinado nome dentro de um determinado módulo. As variáveis temporárias raio e resultado são úteis para o desenvolvimento e depuração, mas uma vez que o código está funcionando, podemos torná-lo mais conciso, compondo as chamadas de função: Code Lua 1 2 3 function calcular_area2(cx, cy, px, py) (Seção 5.4) Funções booleanas Funções podem retornar valores booleanos, que muitas vezes é conveniente para ocultar testes complicados dentro de funções. Por exemplo: Code Lua 1 2 3 4 5 6 7 8 9 10 11 12 13 function numero_negativo(x) Abaixo temos exemplos da função em uso: Code Lua 1 2 3 4 5 6 7 8 9 10 11 function numero_negativo(x) Mesmo a última declaração estando correta, a comparação extra é desnecessária. (Seção 5.5) O tipo function fucntion é outro tipo em Lua, junto de number, string, boolean e nil. Code Lua 1 2 3 4 5 6 function honk() Assim como os outros tipos, as funções podem ser passadas como argumentos para outras funções: Code Lua 1 2 3 4 5 6 7 8 9 function f(n) doto é chamado uma vez. 7 é o argumento para o valor, a função f é passada para func. Este exemplo é um pouco artificial, mas vamos ver situações mais tarde, onde é muito útil passar uma função para uma outra função. (Seção 5.6) Strings multi-linha Além das strings de aspas simples e duplas que vimos pela primeira vez em valores e tipos de dados, o Lua também tem strings de multi-linhas: Code Lua 1 2 print(type([[Eu sou uma string!]])) Elas podem conter aspas simples e duplas dentro delas: Code Lua 1 2 print([["Eu sou uma string!" 'hey!']]) E finalmente, elas podem abranger várias linhas: Code Lua 1 2 3 4 5 6 7 8 9 10 print([[M (Seção 5) Exercícios 1. Escreva uma função chama compare que retorna 1 se a > b, 0 se a == b, e -1 se a < b. Resolução Code Lua 1 2 3 4 5 6 7 8 9 function compare(a, b) 2. Escreva uma função (com o menor número de linhas possível) que retorne 0 quando um número for par, e 1 quando for ímpar. Resolução Code Lua 1 2 3 function checar(x) |
7 | ||
Seção 6 (Seção 6) Iteração (Seção 6.1) Atribuição múltipla Como você pode ter descoberto, é permitido fazer mais de uma atribuição para a mesma variável. Uma nova atribuição faz uma variável existente se referir a um novo valor (e parar de se referir ao valor antigo). Code Lua 1 2 3 4 local dia = "segunda" O resultado do código acima é "segunda" e "terça" porque a primeira vez que dia é mostrado, seu valor é segunda, e a segunda vez, seu valor é terça. Com a atribuição múltipla é especialmente importante distinguir entre uma operação de atribuição e uma declaração de igualdade. Como o Lua usa o sinal de igual (=) para atribuição, é tentador interpretar uma instrução como a = b como uma declaração de igualdade. Mas não é isso! Primeiro, a igualdade é simétrica e a atribuição não é. Por exemplo, em matemática, se a = 7 então 7 = a. Mas em Lua, a declaração a = 7 é correta e 7 = a não é. Além disso, em matemática, uma declaração de igualdade é sempre verdadeira. Se a = b agora, então a será sempre igual a b. Em Lua, uma instrução de atribuição pode tornar duas variáveis iguais, mas elas não precisam permanecer assim. (Seção 6.2) Atualizando variáveis Uma das formas mais comuns de atribuição múltipla é uma atualização, onde o novo valor da variável depende do antigo. Code Lua 1 x = x + 1 O código acima significa: obter o valor atual de x, adicionar um e, em seguida, atualizar x com o novo valor. Se você tentar atualizar uma variável que não existe, você obterá um erro, pois o Lua avaliará a expressão no lado direito do operador de atribuição antes de atribuir o valor resultante ao nome à esquerda: Code Lua 1 2 x = x + 1 Antes de poder atualizar uma variável, é preciso inicializá-la, geralmente com uma atribuição simples: Code Lua 1 2 local x = 9 Atualizar uma variável adicionando 1 é chamado de incremento, subtrair 1 é chamado de um decréscimo. (Seção 6.3) A declaração while Os computadores são frequentemente usados para automatizar tarefas repetitivas. Repetir tarefas idênticas ou semelhantes sem cometer erros é algo que os computadores fazem bem e as pessoas fazem mal. A execução repetida de um conjunto de instruções é chamada de iteração. Como a iteração é tão comum, o Lua fornece vários recursos de idioma para facilitar. O primeiro recurso que vamos olhar é a declaração while. Aqui está uma função chamada contador que demonstra o uso da instrução while: Code Lua 1 2 3 4 5 6 7 function contador(n) Você pode quase ler a declaração while como se fosse inglês. Isso significa que, enquanto n for maior que 0, continue exibindo o valor de n e, em seguida, reduza o valor de n por 1. Quando você chegar a 0, exiba a palavra decolar! Mais formalmente, aqui está o fluxo de execução de uma declaração while:
2. Se a condição for false, saia da instrução while e continue a execução na próxima instrução. 3. Se a condição for true, execute cada uma das instruções no corpo e, em seguida, volte para a etapa 1. Este tipo de fluxo é chamado de um loop porque a terceira etapa "circula" de volta para o topo. Observe que, se a condição for false na primeira vez através do loop, as instruções dentro do loop nunca serão executadas. O corpo do loop deve alterar o valor de uma ou mais variáveis para que, eventualmente, a condição se torne falsa e o loop seja encerrado. Caso contrário, o loop será repetido para sempre, que é chamado um loop infinito. Uma fonte infinita de diversão para os cientistas da computação é a observação de que as direções shampoo, espume, enxague, repita[i/] são um loop infinito. No caso da contagem regressiva na função contador, podemos provar que o loop termina porque sabemos que o valor de n é finito, e podemos ver que o valor de n fica menor a cada vez através do loop, por isso, eventualmente, temos de chegar a 0. Em outros casos, não é tão fácil de dizer. (Seção 6.4) Encapsulamento e generalização Encapsulamento é o processo de envolver um pedaço de código em uma função, permitindo que você tire proveito de todas as coisas boas que funções oferecem. Você já viu exemplos de encapsulamento: iniciar na seção 3, numero_absoluto na seção 5. Generalização significa tomar algo específico, como mostrar os múltiplos de 2, e torná-lo mais geral, como mostrar os múltiplos de qualquer número inteiro. Essa função encapsula um loop e generaliza ele para mostrar múltiplos de n: Code Lua 1 2 3 4 5 6 7 8 9 10 function mostrar_multiplos(n) Para encapsular, tudo o que tínhamos a fazer era adicionar a primeira linha, que declara o nome da função e a lista de parâmetros e seu demilitador(end). Para generalizar, tudo o que tínhamos a fazer era substituir o valor 2 com o parâmetro n. A seção 6 será mais curta pois será melhor discutida na seção 7. |