Sign in to follow this  
.Dev

[CURSO] Básico de Lua 05

Recommended Posts

Posted (edited)

Post Anterior: 

 

Eai pessoal tudo bom? Continuando o Curso básico, hoje vamos um pouco sobre tabelas:

 

Tabelas

Tabelas em Lua é um assunto bem interessante, porque elas podem ser classificadas como varias coisas diferentes, e pode não fazer muito sentido agora, mas é só continuar com o post que vão compreender. Para começar podemos classificar tabelas como:

  • Arrays - Sequencias de valores numéricos;
  • Dicionários - Conteúdo com Chaves e Valores associados;
  • Objetos  - Classes e Módulos, com atributos e métodos.

Mas antes de mais nada, vamos entender como se declara uma tabela. Como explicado anteriormente, as variáveis em Lua são dinâmicas, portanto, basta declarar a mesma da forma correta que o próprio Lua se encarrega de compreender e alocar o espaço especifico. Para se declarar uma tabela, nos usamos o  construtor de tabelas que consiste em um par de chaves "{ --bloco-- }", então para o nosso exemplo ficaria assim:

 

local tabela = {};

 

Assim com o exemplo acima, nos criamos um espaço alocado com o nome de "tabela", e demos a ele um espaço dinâmico. Essa é uma das características das tabelas, como eu expliquei nos posts anteriores, as variáveis em Lua recebem geralmente 1 único valor, por exemplo: 

 

local nome = "dev";

 

Caso eu tente passar 2 ou mais valores ele vai retornar nil em ambos os caras por exemplo:

 

local nome, idade = 'dev', 22;

 

Porque o espaço alocado não é dinâmico, e sim o tipo da variável, no caso das tabelas isso não acontece, eu poderia simplesmente armazenar quantos valores eu quisesse.

 

local num = {11, 22, 30};

 

e caso eu desse print receberia a resposta de todos eles normalmente. Mas para darmos um print nos teríamos que passar o index, e alguns de vocês podem estar se perguntando, "Oque diabos é um index?".

Vamos definir o index como um ponto de partida para facilitar o entendimento. Se estivessemos falando da linguagem C por exemplo, o primeiro index ou seja o ponto de partida, seria 0, mas Lua se utiliza do ponto 1.

Só para facilitar o entendimento, nos poderíamos escrever a tabela dessa forma:

 

local num = {[1] = 11, [2] = 22, [3] = 30};

 

**Esse tipo de organização é feita automaticamente pelo Lua, portanto não é necessário escrever desse jeito.**

 

Como podem ver a organização é definida da seguinte forma: tabela = {[index] = valor}; Então para visualizarmos o conteúdo dentro de uma tabela, teríamos que passar o index da mesma da seguinte forma:

print(num[1]) res => [ 11 ];
print(num[2]) res => [ 22 ];
print(num[3]) res => [ 30 ];

 

ou poderíamos executar um for para facilitar a vida:

for i=1, #num do 
    print(num[i])
end 

 

que o resultado seria => [11 , 22, 30]; -- Lembrando que eu já expliquei como funciona o for.

 

Só para explicar a vocês o "#" é o "Operador de Comprimento", ele verificar quantos index a tabela possui, e como vocês devem lembrar podemos ler o for como PARA valor, max/min incremento FAÇA;

 

**Só para esclarecimento, o # só serve para index numéricos.**

 

Como tabelas em Lua são estruturas básicas de dados, nós podemos armazenar informações em tabelas de outras formas, como foi explicado logo acima o método arrays, nos também podemos utilizar o dicionário:

local usuario = {
    nome = 'Carlos',
    idade = 25
};

 

Como eu expliquei logo acima, dicionário consiste em uma chave + valor. No exemplo acima, a tabela "usuarios" recebeu 2 chaves com seus valores, se déssemos um print por exemplo:

 

print(usuarios[1]) res => [ nil ] -- Receberíamos nil, pelo fato de termos alterado o index 1 para "nome".

 

Quando se trata de nomes (strings) nos podemos utilizar 2 métodos para acionar a data:

 

tabela['chave'] ou tabela.chave 

 

por exemplo:

print(usuarios['nome']) res => [ Carlos ];

print(usuarios.nome) res => [ Carlos ];

 

Ambas as formas estão corretas, mas a segunda se torna bem mais pratica que a primeira. Lembrando que, caso a chave possua espaço, é necessário utilizar a primeira, por exemplo:

local usuarios = {
    ['nome do usuario'] = 'Carlos'
};

 

print(['nome do usuário']) res => [ Carlos ]; 

 

**Só a critérios de explicação, não se recomenda a utilização de espaços em nome de var ou tabelas.**

 

Assim como no exemplo acima, poderíamos nomear uma chave dessa forma, sem espaço e acessar utilizando o "."

local usuarios = {
    ['nome'] = 'dev'
};

 

print(usuario.nome) res => [ dev ]; 

 

**Podemos executar dessa forma, desde que não haja espaços.**

 

Ainda podemos criar chaves dentro de chaves por exemplo:

local usuarios = {
    ['user'] = {
        ['nome'] = 'carlos',
        ['sobrenome'] = 'andrade'
    },
};

 

E poderíamos acessar da seguinte forma:

print(usuarios.user['nome'])  res => [ Carlos ];

print(usuario.user.sobrenome) res => [ Andrade ];

 

Em relação a objetos podemos entrar mais a fundo em outros posts caso vocês queiram, ainda temos classes e herança e metatabelas para abordar, mas como esse curso é básico  não acho que seria um conteúdo interessante de jogar em cima de quem está começando. 

Para acessar os dados da tabela e modificar o mesmo nos podemos utilizar:

 

local num = {x=11, y=22};

 

Nos podemos modificar o valor da seguinte forma:

 

local num.= 30;

 

ou podemos adicionar um novo campo:

 

local num.= 5;

 

As tabelas ainda nos possibilitam adicionar funções a mesma, e utilizar como objetos e/ou módulos externos e Namespace, como por exemplo:

local tabela = function()
    print('Olá!')
end 

 

Depois poderíamos chamar como uma função normal tabela(); res => [ Olá! ]

 

Também poderíamos passar como:

 

[ local tabela = function(args) end ] ou [ function tabela () end ]

 

E o interessante sobre isso, é que podemos usar as regras de acesso a tabelas que foram explicadas mais a cima, e podemos criar objetos e módulos de execução de código, além de poder salvar como módulos externo e importar com um require.

Mas para fixar melhor vamos utilizar um exemplo de código de vetor:

 

local vector = {}; -- Aqui abrimos a tabela que vai ser utilizada para adição das funções.

local vector.create = function(x,y) -- Aqui criamos um novo index chamado "create" e atribuimos a função a ele.
    return(= x, y = y) 
end

 

**No caso o primeiro X referece ao valor X a ser exportado, e o segundo X o argumento.**

local vector.soma = function(num1, num2) -- Aqui criamos o index "soma" e atribuímos a ele a função.
    resultado = {};                      -- Aqui criamos uma nova tabela, dentro de "soma", que vai armazenar o resultado.
    resultado.= num1.+ num2.x        -- Criamos o index "x", dentro da tabela resultado, e atribuímos a formula.
    resultado.= num1.+ num2.y        -- Criamos o index "y", dentro da tabela resultado, e atribuímos a formula.
    return resultado 
end
local vector.print = function(n)         -- Aqui criamos o index "print", e atribuímos a ele a função.
    print("(" .. n... ", " .. n... ")") 
end


 

num1 = vector.create(,25)   -- Aqui estamos atribuindo o valor aos argumentos e chamando a vector.create como função.
num2 = vector.create(10,50) -- Aqui estamos atribuindo o valor aos argumentos e chamando a vector.create como função.

 

vector.print(num1, num2)    -- Aqui estamos chamando a função "print", como definimos e passando os valores atribuídos a ela.

 

Se fossemos visualizar essa tabela como um todo ela estaria da seguinte forma:

local vector = {
    ['create'] = function(x,y)
        return(= x, y = y) 
    end
    ['soma'] = function(num1, num2)
        resultado = {};                     
        resultado.= num1.+ num2.x        
        resultado.= num1.+ num2.y        
        return resultado 
    end
    ['print'] = function(n)
        print("(" .. n... ", " .. n... ")") 
    end
};

 

Essa seria a visualização completa da tabela, podemos ver como cada função fica em seu espaço e porque o uso do tabela.função retorna.

 

**Podemos chamar esse tipo de construção de modulo/biblioteca, para facilitar o entendimento.**

 

Essas funções como foram definidas acima, podem ser salvas em um arquivo externo e importadas em qualquer script, com o comando require por exemplo:

 

local vector = require(scripts/vector);

 

assim sempre que chamássemos vector.soma e etc, ele serie executado como um modulo, isso se torna bem util para funções uteis do MTA, como isPlayerInACL() e etc.

 

Manipulação de Tabelas

 

Além do que foi explicando, ainda temos como manipular as tabelas de outras forma. Que seria com a utilização da biblioteca do proprio Lua, abaixo vou explicar quais são as manipulações e como utilizar elas:

table.insert (table, [pos,] value) -- Insere uma informação na tabela, na posição (index) desejada. [PUSH]
table.maxn (table)                 -- Retorna o maior index da tabela. [POP]
table.remove (table [, pos])       -- Remove dados da posição especificada da tabela.
table.sort (table [, comp])        -- Ordena os elementos da tabela em uma dada ordem.
table.concat (table [, sep [, i [, j]]]) 

 

Pra facilitar vou dar um exemplo:

 

print(table.concat({"(", n.x,", ", n.y,")"})) 

 

No exemplo acima, nos criamos uma tabela dinamica dentro do print, e concatenamos (juntamos), os valores. Isso é uma boa pratica, pelo fato de quando trabalhamos com  strings muito longas, os valores podem acabar se misturando, então pra evitar o uso de " .. " e resultado de erros, podemos usar o concat. E ainda evitamos o overhead do " .. "

 

Outras funções

next(table, index)                 -- Itera sobre cada um dos elementos na tabela.
unpack(table, index)               -- Retorna uma tupla com os elementos.
pairs(table(t))                    -- Retorna um iterador sobre todos os elementos da tabela.
ipairs(table)                      -- Iterador sobre os indices numericos da tabela. [Parecido com forEach()]

 

**Tupla é uma sequencia finita e ordenada de objetos.**

 

Exemplo de Utilização do pairs e ipairs:

local table = {10, 22, 33, 'dev'};

for index, value in ipairs(table) do 
    print(index, value)
end

 

No exemplo acima estamos imprimindo todos os valores numericos da table, porem o index não chegará até o 4, porque 'dev' é uma string não um int, nesse caso  poderiamos subistituir o ipairs por pairs assim teriamos todos os resultados. [Pairs não tem garantia de ordenação!]

 

No caso do next, é bem simples a utilização vamos pensar nele dessa forma:

local tabela = {40, 12, 85};

print(next(tabela[index] + 1)) -- Isso é só para facilitar a visualização!


 

O next sempre imprime o proximo index, no caso a tabela[0] + 1 é tabela[1] res => [ 40 ];

 

Então se continuarmos seria res => [ 12 ]; E assim por diante.

 

Ainda é possivel passar next(tabela, index);

 

Exemplo de unpack:

local val = {1,2}

function soma(num1, num2)
    return num1 + num2
end
print(soma(val[1], val[2])) res => [ 3 ];

Porem o unpack realiza isso para nos, portanto, poderiamos utilizar:

 

print(soma(unpack(val))) res => [ 3 ];

 

**Unpack funciona apenas em elementos numericos.**

 

Caso queiram, podem postar o código nesse tópico, e caso tenham alguma duvida, deixem logo a baixo. Só lembrando ao pessoal que já entende do assunto, ou pelo menos sabe o básico, vamos ajudar quem ta começando, todo mundo começou sem saber quase nada.

Pessoal, gostaria de saber oque vocês querem no ultimo post sobre Lua, na parte de MTA, exemplos de resources e etc, e porfavor comentem se gostariam de ver um curso intermediario/avançado de Lua, cobrindo os pontos que não abordei durante esses posts.

Edited by .Dev
  • Like 2
  • Thanks 2

Share this post


Link to post
Posted (edited)

Algumas correções:

  • (diversos erros ortográficos e de acentuação, principalmente na palavra "nós")
  • Assim como é opcional usar ponto e vírgula ao final de cada comando, também é opcional usar aspas duplas para cadeia de caracteres ("string"). Supondo que seu objetivo seja ensinar a sintaxe perfeita da linguagem, incluindo as regras opcionais, é preferível que se use aspas duplas para cadeia de caracteres em vez de aspas simples. Dessa forma evitando vícios que causam problemas em outras linguagens, onde 'string' não é permitido.
  • No seu exemplo de ipairs/pairs você cometeu um equívoco: O ipairs irá funcionar normalmente naquele exemplo, pois seus índices são todos inteiros (não declarados no código, indexados automaticamente pelo programa em [1], [2], [3], [4]). O fato de um elemento não ser número não irá influenciar no ipairs, pois o que importa para ele são os índices. Se você quer um exemplo onde ipairs não funciona e precisa do pairs, você precisa declarar os índices sendo pelo menos um deles não inteiro ou então faltando algum índice na sequência. O ipairs não lê quando não encontra o índice seguinte i+1. Ex:
local table = {[1] = 10, [2] = 22, [4] = 33, [5] = "dev"};

for index, value in ipairs(table) do
    print(index, value) -- Só vai retornar o 10 e o 22. Pois o índice [3] não foi encontrado. (erro)
    -- Ele também não vai ler se o elemento do índice for nil. Ou seja se tivesse o [3] = nil, daria o mesmo resultado.
end

-- Se no lugar do [5] fosse [3]. Dai ele iria imprimir todos os valores na ordem dos índices.
--[[
1  10
2  22
3  dev
4  33
]]

-- Se usar pairs, ele vai imprimir todos os valores, mas nem sempre na mesma ordem. O pairs não se importa com a sequência de índices, podendo ser usado até em tabelas com índices não numéricos.
  • Unpack funciona apenas em tabelas com índices inteiros. E funciona em tabelas com elementos não numéricos.
Edited by Lord Henry

Share this post


Link to post

Lord Henry, agradeço ter respondido no tópico. Em relação as aspas simples ou duplas é questão de vicio mesmo, eu mesmo acabo usando geralmente as simples em Lua, é algo que não me confunde em outras linguagens quando necessito das aspas duplas, mas vou prestar mais atenção nisso em relação aos códigos para ajudar o pessoal.

E agradeço pela coreção do ipairs e pairs vai ser util para o pessoal, se estiver tudo bem pra você, vou anexar ao post, ou deixo teu comentario, como achar melhor.

Share this post


Link to post

É preferível que vc edite o post com as correções. Depois posso remover meu comentário.

Share this post


Link to post

Create an account or sign in to comment

You need to be a member in order to leave a comment

Create an account

Sign up for a new account in our community. It's easy!

Register a new account

Sign in

Already have an account? Sign in here.

Sign In Now
Sign in to follow this  

  • Recently Browsing   0 members

    No registered users viewing this page.