Introdução a linguagem Lua, você vai querer aprender também.

Em busca de uma programação poliglota, e entender as vantagens da cada linguagem oferece, iniciei meus estudos na linguagem Lua.

Histórico 

 Lua é uma linguagem de extensão, criada nos laboratórios da PUC-RJ, com o objetivo de ser simples de ser embarcada. Isso é, ele é extremamente pequena, sucinta, de sintaxe simples, esta presente praticamente em qualquer sistema. É uma verdadeira “write once, run everywhere”(bem mais que java). O pacote de Lua, com documentação, código fonte e exemplos tem cerca de 800KBs, apenas o runtime compilado(no linux) tem 150KBs. São 1700 linhas de código C portável, o mesmo código compila em várias plataformas.  

Roda em Unix, Linux, Windows, e em várias plataformas embarcadas, como celulares e setop boxes, robôs entre outros. Pode ser incluída em qualquer aplicação feita em outra linguagem , com quase nenhum overhead. Para ter melhor noção, um interpretador Lua completo em puro Java (tanto J2ME quanto J2SE), tem cerca de 150KBs. É usada como linguagem de extensão em produtos da Adobe, roda no Android, esta no Ginga (da TVDigital), e é muito usada em Jogos, como o sempre citado World of Warcraft.

E por que não fazer tudo em Lua então? Lua foi pensada em extensão de aplicativos, então a biblioteca básica é bem limitada, não possui as milhares de funções para tudo como teria em Java ou PHP ou Ruby ou Python ou Outra. Seus 150KBs incluem apenas o necessário, muito tem disponível em módulos externos, como os do LuaRocks. Embora seja possível para certas aplicações, mas não é foco.

Enfim, vendido o peixe de Lua. Agora é demonstrar, afinal “Show me the code”.

Exemplos 

Primeiro o essencial, lua é Imperativo, tem funções como cidadão de primeira classe(ah, deu para entender) e tudo é armazenado em tabelas. Tabelas são como arrays, mas são tabelas, depois eu explico. É tipagem dinamica, essencialmente não é orientada a objetos(pode ser simulado), possui escopo e é modular. Vamos ao exemplo.  

  -- rss.test.lua

local xml = dofile("xml.lua")
local sample = "<?xml ?><channel><rss><title>Lua Rock!</title>"
sample = sample .. "<item><title>Item 1</title></item>"
sample = sample .. "<item><title>Item 2</title></item>"
sample = sample .. "</rss></channel>";
local rss = xml.parse_rss(sample)
assert(rss[1].title == "Item 1","Invalid Item 1 title")
assert(rss[2].title == "Item 2","Invalid Item 2 title")
print("rss tests ok")

Esse simples exemplo é o arquivo de testes de uma biblioteca de parser de rss que uso. O uso do modificador “local” indica o escopo mais fechado possível dessa variável. O não uso de “local” implica numa variável “global”, visível em toda a aplicação.  

A função “dofile” carrega um arquivo (como se fosse um include), esse arquivo carregado pode retornar uma ou mais variáveis, no caso o xml.lua me retorna uma tabela.

A chamada de função é normal, no caso o xml é uma tabela, e um dos seus índices (parse_rss) é uma função que recebe um argumento e retorna uma tabela.

  Fato interessante sobre tabelas em Lua, é que os índices numéricos começam em 1, e não em 0 como estamos acostumados.

  Em “rss[1].title”, eu pego o item de índice 1(o primeiro), da tabela “rss” e o item de índice title dentro desta. No “assert” eu garanto que a expressão retorne True, do contrário levanto o erro no segundo argumento. 

  O arquivo de rss é assim: 

  -- rss.lua
local xml = dofile("utils/xml.lua")
xml.parse_rss = function (str)
local rss = {};
local t = xml.parse(str)
local channel = t[2][1]
for k,v in pairs(channel) do
local label = v['label']
if label == "item" then
local item = {}
for k,v in pairs(v) do
local label = v['label']
if label and v[1] then
item[label] = v[1]
end -- if label and value
end --for pairs in v
table.insert(rss,item)
end -- if is item
end -- for item in channel
return rss
end
return xml

 

Novamente eu carrego um parser xml externo, e na tabela xml eu adcione um índice, o parse_rss. Nesse índice eu ligo uma função, que recebe um argumento. Veja que não tem tipo fixo, eu poderia usar assert para garantir o tipo.

Eu defino então a variável “rss” como uma tabela vazia. Então faço um loop for nos itens retornados pelo parser xml. A função “pairs” retorna as chaves (k) e os valores(v) de uma tabela.

Temos então um IF padrão, nova tabela e mais um for. Então eu uso o “insert”, “table”, que é uma tabela embutida no core do lua. E retorno o RSS, o arquivo então retorna a tabela com as funções.

O parser XML é deveras grande, não vale a pena passa-lo aqui, e isso tudo foi apenas para dar um visão geral na estrutura da sintaxe da linguagem. Vamos agora no passo-a-passo de verdade.

Tutorial 

Em Lua, funções são objetos de primeira classe, então podemos por exemplo ter funções “curried”, como no exemplo abaixo:

  -- curry.lua

function soma(n)
return function(n2)
return n + n2
end
end

local f2 = soma(2)
local soma2e3 = f2(3)
assert(soma2e3 == 5)

 

Podemos levar um pouco alem:

  
-- curry.lua
local somador = function(n)
local soma = n
function f(n2)
if type(n2) == "number" then
soma = soma + n2
return f
else
return soma
end
end
return f
end

local total = somador (1) (2) (3) ()
print(total)

local somador = function (itens)
assert(type(itens) == "table")
local soma = 0;
for k,v in pairs(itens) do
soma = soma + v
end
return soma, #itens
end

local total,n = somador {
1,2,3
}
print(total,n)

local somador = function(```)
local soma = 0;
for k,v in pairs(arg)do
if type(k) == "number" then
soma = soma + v
end
end
return soma
end

local total = somador(1,2,3)
print(total)

 

São as várias formas de fazer a mesma coisa, veja no penúltimo somador uma característica legal, uma função pode retornar mais de uma variável.

Agora que você conhece como fazer funções, loops e condicionais, vamos tratar das tais tabelas.

  --tabelas.lua
local tab = {
"um","dois",
x="3",
y=function() return "hello" end
}
table.insert(tab,"cinco")
table.remove(tab,2)
local final = table.concat(tab," , ") -- apenas numéricos
print(tab[1], tab[2], tab["x"],tab.y,tab["y"](),tab[5],final)

 

Entendeu?

A ultima parte que quero tratar nesse texto é sobre coroutines, que são as “threads” do lua, incluído no core da linguagem, exemplo geral:

  --co.lua
local hello = coroutine.create(function(name)
print ("hello "..name)
end)


coroutine.resume(hello,"diogo")

local hello2 = coroutine.create(function(name)
repeat
print("hello you, "..name)
name = coroutine.yield(name)
until not type(name) == "string"
end)

local h2 = coroutine.resume(hello2,"diogo")
local h3 = coroutine.resume(hello2,"diego")
local h3 = coroutine.resume(hello2)
local h4 = coroutine.resume(hello2)

 

Acho que com esses exemplo já dá para decidir se quer ou não aprender Lua. Caso queira, o melhor lugar é a wiki da documentação de lua.

  Termino com um exemplo de uso real, uma função que realiza uma busca na wikipedia e retorna o resultado, o JSON eu achei na internet, e o http usa o Lua Socket, o wikipedia.lua.  

3 ideias sobre “Introdução a linguagem Lua, você vai querer aprender também.

  1. Legal! Me interessei muito por essa linguagem, pois ela é simples e leve, não é como C ou C++ que são muito complexas, por isso quero aprender LUA, mas o site http://lua-users.org/wiki/LuaOrgGuide é todo em inglês, e isso dificulta um pouco. Não tem nenhum site em portugês, não? Se tiver por favor me deêm um link. (me mandem por E-Mail) :)

Comentários encerrados.