Você está na página 1de 10

Introdução à linguagem de programação Lua

Lua é uma linguagem de programação de extensão desenvolvida para suportar


programação procedural geral com facilidades de descrição de dados. Ela foi projetada
para ser uma linguagem de scripting poderosa e leve para qualquer programador usar.
Conheci Lua em 2010, quando comecei a programar para Corona SDK, o meu framework
mobile multiplataforma favorito. É uma linguagem incrivelmente simples e poderosa para
criar a lógica de jogos, sendo usada não apenas por desenvolvedores independentes como
eu, mas por grandes empresas como EA e Blizzard em seus jogos.
Muitos desenvolvedores que compraram o livro que traduzi sobre Corona SDK me pediram
um apêndice em Português sobre o básico de Lua, e como não tenho o cadastro de todos
para enviar uma versão atualizada do livro, resolvi publicar aqui um post bem extenso que
cobre todo o básico dessa linguagem de programação para que usem como referência de
consulta. O próprio livro ensina esses conceitos ao longo de suas páginas, mas aqui agrupo
todos os ensinamentos em um só lugar e espero que se torne mais fácil de tirar suas
dúvidas.

Convenções
Em Lua os nomes (também chamados de identificadores) podem ser qualquer conjunto de
letras, números e underscore, desde que não comece com número, coincidindo com a
definição do que é um nome em muitas linguagens. Esses nomes e identificadores são
usados em variáveis e campos de tables (que veremos mais adiante).
As seguintes palavras-chave são reservadas e não podem ser usadas como nomes:
and break do else elseif end false
for function if in local nil not
or repeat return then true until while

Os seguintes caracteres denotam tokens, símbolos especiais da linguagem:


+ - * / % ^ #
== ~= <= >= < > =
( ) { } [ ]
; : , . .. ...

Lua é uma linguagem case-sensitive, ou seja, diferencia maiúsculas e minúsculas, ou seja,


and e AND são coisas diferentes pra ela, então tome cuidado. Como convenção, nomes
começando com um underscore seguido de letras maiúsculas (ex: _VERSION) são
reservadas para variáveis globais internas usados pela própria linguagem.
Um comentário começa com dois traços (hífens) antes do texto que desejamos comentar e
“comentam” a linha inteira. Você também pode comentar um bloco completo de código
cercando-o com –[[ e –]]. Para descomentar o mesmo bloco, simplesmente adicione outro
hífem no início do bloco de comentário, como em —[[.
--comentário de uma linha

--[[ comentário com mais de uma linha


print( 10 )
print( 15 )
--]]

Um valor numérico constante pode ser escrito com uma parte decimal opcional ou mesmo
um expoente decimal. Lua também aceita constantes hexadecimais inteiras, prefixando-as
com 0x. Exemplos de valores numéricos válidos são:
3 3.0 3.1416 314.16e-2 0.31416E1 0xff 0x56

Tipos de Valores
Lua é uma linguagem de tipagem dinâmica. Isto significa que as variáveis não possuem
tipos; somente valores possuem. Não existem definições de tipo nesta linguagem. Todos
valores carregam seu próprio tipo.
Todos valores em Lua são valores de primeira classe. Isto significa que todos valores
podem ser armazenados em variáveis, passadas como argumentos para outras funções e
retornados como resultado.
Os tipos básicos que você deve ter em mente são:
 nil — o tipo do valor nil, cuja principal diferença é ser diferente de qualquer outro valor;
usualmente representa a ausência de um valor útil.
 boolean — o tipo dos valores false e true. Os valores nil e false em uma condição
tornam-a falsa; qualquer outro valor é true.
 number — representa números reais (com ponto-flutuante de dupla precisão).
 string — representa arrays de caracteres. Lua trabalha apenas com caracteres de
8-bits.
 function — veja mais adiante.
 table — o único mecanismo para estrutura dados em Lua. Veja mais adiante.

Lua fornece conversão automática entre strings e números em tempo de execução. Qualquer
operação aritmética aplicado a uma string tenta converter a string para um número, seguindo
as regras normais de conversão. No entanto, toda vez que um número é usado onde uma
string deveria ser usada, ele será convertido também. Para um controle maior de como os
números se tornam strings, use a função string.format da biblioteca string.

Tables
Tables são a única estrutura de dados em Lua. Elas implementam arrays associativos,
significando que os arrays podem ser indexados não somente pelas suas posições (índices),
mas por qualquer valor exceto nil. Tables são heterogêneas e podem conter valores de
qualquer tipo exceto nil.
Para representar propriedades, Lua usa o nome do campo como um índice. A linguagem
suporta esta representação fornecendo a.nome como o “syntax sugar” a[“nome”].
Como índices, o valor de um campo de uma table pode ser de qualquer tipo exceto nil.
Devido ao fato de functions serem valores de primeira-classe, você pode guardar functions
em tables também, embora tables não possam carregar métodos (ver adiante).
Tables são objetos: variáveis que não verdade não contém seus valores, somente
referências para eles. Associação, passagem de parâmetros e retorno de funções sempre
manipulam referências como valores; estas operações não implicam em nenhum tipo de
cópia.
Para inicializar uma variável como sendo uma table usando chaves: {}.
t = {} --cria uma table

k = "x"
t[k] = 3.14 --novo registro na table, com a chave="x"
e valor=3.14

print( t[k] ) --> 3.14


print( t["x"] ) --> 3.14
print( t.x ) --> 3.14

t[2] = "foo" --novo registro na tabela, com chave=2 e


valor="foo"

print( t[2] ) --> "foo"

Acessando registros
No exemplo acima, o registro com o nome “x” foi acessado de duas maneiras: como uma
propriedade usando o operador ‘ponto’ t.x e como um índice de array usando t[“x”].
Um erro comum é confundir t.x com t[x]. O primeiro é equivalente ao t[“x”]: uma table
indexada pela string “x”. O segundo é uma table indexada pelo valor da variável x.

Importante
Muitas APIs do Corona retornam objetos. Você pode manipular as propriedades
documentadas destes objetos assim como faria com qualquer propriedade de table. Você
pode até mesmo adicionar suas próprias propriedades desde que não use um underscore
no início delas, pois isso é reservado pelo Corona.

Variáveis
Variáveis são locais em memória para adicionar valores. Existem três tipos de variáveis em
Lua: global, local e campo de table. Qualquer variável não-inicializada é por padrão nil.

Global

Variáveis globais não precisam de declaração. Você simplesmente associa um valor para
criá-la:
print( s ) --> nil

s = "One million dollars"

print( s ) --> One million dollars

Variáveis globais existem enquanto sua aplicação está rodando. Você pode excluir uma
variável global atribuindo nil à ela.
s = nil
print( s ) --> nil

Local

Variáveis locais são declaradas usando a palavra local:


x = 1 --global
local y = 10 --local

Diferente de variáveis globais, variáveis locais são visíveis somente no bloco onde elas
estão declaradas. O escopo de uma variável local começo logo após sua declaração e
termina no final do bloco.
a = 10
local i = 1

while ( i <= 10 ) do
local a = i*i --outra variável 'a', local neste bloco while
print( a ) --> 1, 4, 9, 16, 25, ...
i = i + 1
end

print( a ) --> 10 (a variável 'a' global)

Campos de Table

Campos de table são somente elementos da tabela em si. Você indexa-os dentro de um
array para atribuir valores à um campo.

t = { foo="hello" } --cria uma table com a propriedade "foo"


print( t.foo ) --> "hello"

t.foo = "bye" --atribui um novo valor para a propriedade "foo"


print( t.foo ) --> "bye"

t.bar = 10 --cria uma nova propriedade chamada "bar"


print( t.bar ) --> 10
print( t["bar"] ) --> 10

Expressões

Operações Aritméticas

Lua suporta os operadores de aritmética binária básica:

+ (adição) - (subtração)
* (multiplicação) / (divisão)
% (módulo) ^ (exponenciação)

Se os operandos são números ou strings que podem ser convertidos para números, todas
operações fazem exatamente o que você imagina que elas façam.

Operadores Relacionais
Os operadores relacionais de Lua são
== (igual que)
~= (diferente que)
< (menor que)
> (maior que)
<= (menor ou igual que)
>= (maior ou igual que)

Estas operações sempre resultam em true ou false.


Quando temos strings e/ou números como operandos, o operador de igualdade (==)
primeiro compara os tipos dos mesmos. Se forem diferentes, o resultado é false. Caso
contrário, os valores são então comparados. Já objetos são comparados pela referência, ou
seja, apenas resultam em true se ambos forem o mesmo objeto, afinal, cads novo objeto
criado é completamente diferente de todos os outros, do ponto de vista de referência.
A regra de conversão automática citada mais cedo neste post não se aplica à comparações
de igualdade, ou seja, “0” == 0 retorna false.

Operadores Lógicos

Os operadores lógicos em Lua são and, or, e not. Todos operadores lógicos consideram
false e nil como false e qualquer outra coisa como true.
 and — o operador de conjunção retorna seu primeiro argumento se ele for false ou
nil, caso contrário retorna seu segundo argumento.
 or — o operador de disjunção retorna seu primeiro argumento se seu valor for
diferente de nil e false; caso contrário retorna seu segundo argumento.
 not — o operador de negação retorna o oposto do valor do argumento.

Tanto and quanto or são curto-circuitados, ou seja, somente analisam o segundo


argumento se necessário.
10 or 20 --> 10
10 or error() --> 10
nil or "a" --> "a"
nil and 10 --> nil
false and error() --> false
false and nil --> false
false or nil --> nil
10 and 20 --> 20

Concatenação
A concatenção de string em Lua é denotada por dois pontos seguidos (..). Se ambos
operandos forem strings ou números, eles serão convertidos para strings de acordo com as
regras de conversão.
local s = "foo".."10"

Operador length

O operador length é denotado pelo operador unário #. O length de uma string é seu número
de bytes – sendo que cada caracter tem o tamanho de 1 byte.
O length de uma table é definido por qualquer índice n tal que t[n] não seja nil e t[n+1] seja
nil; mais do que isso, se t[1] é nil, n pode ser zero. Idealmente um array não deve conter
valores nil, caso contrário, o operador length pode se comportar de maneiras inesperadas.

Precedência

A precedência de operadores em Lua segue a seguinte tabela, do menor para o de


maior prioridade:

or
and
< > <= >= ~= ==
..
+ -
* / %
not # - (unary)
^

Como usual, você pode usar parênteses para mudar a precedência de uma expressão. Os
operadores de concatenação (..) e exponenciação (^) computam primeiro o elemento da
direita. Os demais operadores começam pela esquerda.

Funções
Funções simples funcionam exatamente como esperado: você fornece argumentos como
entradas (entre parênteses), a função executa algumas tarefas, e os resultados podem ser
retornados.
A seguir, maneiras comuns de declarar funções:
local function f ()
--body
end

local f = function()
--body
end

function f ()
--body
end

f = function ()
--body
end

Functions podem ser variáveis, logo uma table pode armazená-las como propriedades. Isto
permite usos muito flexíveis para tables. Ela pode ser usada pata agrupar logicamente uma
família de funções, por exemplo a biblioteca math. Neste caso, para calcular o seno de 100,
você pode escrever math.sin(100). Note que math é uma mera table, e a propriedade sin é
a função na verdade.

Métodos em Objetos

Objetos em Lua são representados por tables. Objetos de tela (retângulos, imagens, etc) e
o objeto global Runtime são todos objetos. Como a biblioteca math, estes objetos
armazenam métodos de instância como propriedades. Uma diferença importante é a
sintaxe de métodos vs functions: você usa dois pontos entre o objeto e seu método (:) ao
invés do ponto tradicional das functions.

Regras de Escopo
Lua é uma linguagem com escopo léxico. O escopo da variáveis começam no primeiro
comando depois da sua declaração e terminam no final do bloco mais interno que inclua a
declaração da mesma.
x = 10 --variável global
do --novo bloco
local x = x --novo 'x' com valor 10
print(x) --> 10
x = x+1
do --outro bloco
local x = x+1 --outro 'x'
print(x) --> 12
end
print(x) --> 11
end
print(x) --> 10 (o global)
Note que, em uma declaração como local x = x, o novo x sendo declarado não está no
escopo ainda, e então o segundo x refere-se à variável de fora.
Devido às regras de escopo léxico, variáveis locais podem ser livremente acessada por
functions definidas dentro do seu escopo. Uma variável local usada por uma função interna
é chamada de upvalue, ou variável local externa, dentro da função interna.
Note que cada execução de um comando local define novas variáveis locais:
a = {}
local x = 20
for i = 1,10 do
local y = 0
a[i] = function () y = y+1; return x+y end
end

O loop cria dez instâncias de closures (funções anônimas). Cada um desses closures usam
uma variável y diferente, enquanto todos compartilham o mesmo x.

Alocação de Memória
Dispositivos móveis possuem memória limitada disponível para uso, então tome muito
cuidado com o total de memória alocada em sua aplicação.
Lua executa limpeza de memória automática. Isto significa que você não tem de se
preocupar sobre alocar memória para novos objetos, nem mesmo precisa liberar objetos da
memória manualmente. A própria linguagem executa um coletor de lixo de tempos em
tempos e coleta todos objetos mortos (órfãos) e toda memória usada pelo Lua está sujeita
ao coletor automático.
No entanto, cabe à você dizer ao Lua o que é lixo. Por exemplo, qualquer coisa
armazenada em uma variável global não é considerado lixo, mesmo que sua aplicação não
use mais essa variável. Similarmente, qualquer coisa armazenada em uma table jamais
será considerada lixo também – independente se foi instanciado localmente ou não. Nestes
casos, cabe à você atribuir nil às variáveis que não deseja mais usar.
Objetos de tela em Corona exigem um passo adicional. Você deve primeiro remover o
objeto da hierarquia da tela usando object:removeSelf() ou display.remove( object ), e
depois defini-lo como nil.
myObject:removeSelf()
--OU...
display.remove ( myObject )

myObject = nil

Diferenças de Sintaxe
Algumas diferenças entre a sintaxe de Lua e outras linguagens valem a pena ser citadas
pois podem prevenir alguns erros de compilação:
 ponto e vírgula — são opcionais no final de cada linha de código.
 chaves — aqui elas são usadas apenas para inicializar tables. O escopo dos blocos de
código são delimitados por do e end.
 if – then – else — se você veio do C, Java, Javascript, eyc., um erro comum que você
irá cometer seguidamente é o de esquecer de colocar then ao final da condição do
if/elseif. Outro erro comum é o de escrever ‘else if’, quando o correto é elseif.
 arrays — em Lua eles começam na posição 1, ou seja, a primeira posição de uma table
t é t[1], não t[0].
 múltiplos valores de retorno — um recurso não-convencional mas útil em Lua é a
habilidade de uma function retornar mais de um resultado.
 atribuição múltipla — esse recurso oferece uma maneira conveniente de trocar valores.
O comando x,y = y,x irá trocar x por y e vice-versa.

 operador ternário (? — Lua não oferece um equivalente, embora uma expressão


‘(a and b) or c’ ofereça algo semelhante desde que b não seja false.

O conteúdo deste post foi retirado da referência em Português sobre Lua no site oficial,
permitido pela própria licença da linguagem: http://www.lua.org/manual/5.1/pt/

Você também pode gostar