[Lua] Enum Hitskin_logo Hitskin.com

Isto é uma pré-visualização de um tema em Hitskin.com
Instalar o temaVoltar para a ficha do tema

Aldeia RPG
Gostaria de reagir a esta mensagem? Crie uma conta em poucos cliques ou inicie sessão para continuar.

[Lua] Enum

2 participantes

Ir para baixo

[Lua] Enum Empty [Lua] Enum

Mensagem por Paulo Soreto Sex Out 27, 2017 6:08 pm

Enum é uma lista de certa forma uma lista de identificadores que possuem valores numéricos (variam de acordo com a definição do usuário e de linguagem).
Na maioria dos casos o uso é basicamente o seguinte:
Código:
enum Abc {
  A = 1,
  B,
  C
}
Abc.A // 1
Abc.B // 2
Abc.C // 3

Não da pra obter o mesmo resultado em Lua mas a gente pode chegar perto. A representação em Lua para quem ainda não mentalizou seria assim:
Código:
local Abc = {
  A = 1,
  B = 2,
  C = 3
}
print(Abc.A) -- 1
print(Abc.B) -- 2
print(Abc.C) -- 3

Nota-se que temos que definir o valor de cada item manualmente e o resultado final é uma table que pode ser modificada (adicionar ou remover itens por exemplo podem fazer com que o funcionamento do enum se torne inválido).

Nós podemos corrigir esse problema de definir novos valores de uma forma muito simples: usando metatables.
Código:
local Abc = setmetatable({
  A = 1,
  B = 2,
  C = 3
}, {
  __newindex = function()
    error('nenhum elemento pode ser adicionado a um enum')
  end
})

Abc.X = 4
Se executrarmos o código acima teremos a seguinte mensagem de erro:
Código:
nenhum elemento pode ser adicionado a um enum
Isso acontece por que definimos uma nova metatable para a table que foi atribuida a variável Abc (falarei sobre metatables em outro post).

Quando um valor é adicionado a uma table (seja pelo table.insert ou uma atribuição direta: a = b) a função __newindex definida dentro da metatable do objeto é chamada. Para impedir que novos valores sejam adicionados nós sobreescrevemos esta função e liberamos um erro caso ela seja chamada.

Ou seja, se por engano você ou alguém tentar definir um novo campo no enum dessa forma o sistema irá encontrar um erro. Isso não é tudo que podemos fazer, meu objetivo é no final deste post vocẽs consigam declarar enumerações em lua de forma semelhante a linguagens como C (eu disse semelhante >.>)

O primeiro passo pra atingirmos esse objetivo é pararmos de usar diretamente a table para definir os valores do enum. Para isso vamos criar uma função chamada enum e ela retornará uma table com todos os elementos definidos a partir dos parametros recebidos. Seria mais ou menos assim:
Código:
local abc = enum('A', 'B', 'C')
print(abc.A) -- 1
print(abc.B) -- 2
print(abc.C) -- 3
E aqui temos nossa função:
Código:
function enum(...)
  local args, ntable, count = {...}, {}, 1
  for i = 1, #args do
    ntable[args[i]] = count
    count = count + 1
  end
  return setmetatable(ntable, { __newindex = function()
    error('nenhum elemento pode ser adicionado a um enum')
  end})
end
Na primeira linha dentro dela nós definimos três variáveis que são respectivamente: os argumentos passados pra função, a table que será retornada pela função e uma variável que é usada como contador. Após isso, em um loop nós pegamos cada argumento passado e adicionamos a nova table, o valor é o valor atual do count.

Acredito que alguns de vocês já percebeu que tem um problema na nossa implementação, ela não permite atribuir valores aos elementos. Para resolvermos isso, ao inves de recebermos os elementos que farão parte do enum por direto do argumentos, vamos passar eles para uma table.

O código acima com essas modificações é:
Código:
function enum(otable)
  local ntable, count = {}, 1
  for i = 1, #otable do
    ntable[otable[i]] = count
    count = count + 1
  end
  return setmetatable(ntable, { __newindex = function()
    error('nenhum elemento pode ser adicionado a um enum')
  end})
end

local abc = enum({'A', 'B', 'C'})
print(abc.A) -- 1
print(abc.B) -- 2
print(abc.C) -- 3

Agora que estamos utilizando uma table para passar os elementos podemos mudar um pouco a forma como usamos. Quando o argumento de uma função é passado como um objeto literal de string ou table (desde que apenas um argumento) o uso de parêntesis se torna desnecessário, logo temos o seguinte código:
Código:
local abc = enum { 'A', 'B', 'C' }
print(abc.A) -- 1
print(abc.B) -- 2
print(abc.C) -- 3
Ou melhor ainda:
Código:
local abc = enum {
  'A',
  'B',
  'C'
}
print(abc.A) -- 1
print(abc.B) -- 2
print(abc.C) -- 3
Agora nosso sistema está ganhando forma mas o problema de atribuir valores para os elementos durante a definição do enum ainda persiste. Para resolvermos isso percisaremos verificar o tipo de cada chave dentro da table passada, se for uma chave numérica (ou índice se preferir) significa que o campo que passamos  é somente o nome do elemento, sem valor algum. Nesse caso o código anterior persiste mas quando a chave for do tipo string precisaremos adicionar a chave como nome do elemento.

Para fazer uma parte do trabalho usaremos a função pairs que retorna dois valores (chave e valor) para cada item de uma table. O código descrito seria o seguinte:
Código:
function enum(otable)
  local ntable, count = {}, 1
  for key, value in pairs(otable) do
    local tk = type(key)
    if tk == 'number' then
      ntable[value] = count
      count = count + 1
    elseif tk == 'string' then
      ntable[key] = value
    else
      error('nenhum objeto do tipo "'..tk..'" pode ser usado como elemento de um enum')
    end
  end
  return setmetatable(ntable, { __newindex = function()
    error('nenhum elemento pode ser adicionado a um enum')
  end})
end

local abc = enum {
  'A',
  B = 3,
  'C'
}
print(abc.A) -- 1
print(abc.B) -- 3
print(abc.C) -- 2
Agora temos uma implementação funcional enum que você pode usar no seu projeto em lua. Lembrando que todo o custo de processamento é na inicialização do objeto, após isso ele age como uma table normal.

Espero que tenham gostado do tutorial, se tiver feedback posso fazer outros posts sobre Lua.

_________________
[Lua] Enum FwYnoXI
Paulo Soreto
Paulo Soreto
Lenda
Lenda

Mensagens : 1980
Créditos : 367

Ficha do personagem
Nível: 1
Experiência:
[Lua] Enum Left_bar_bleue0/0[Lua] Enum Empty_bar_bleue  (0/0)
Vida:
[Lua] Enum Left_bar_bleue30/30[Lua] Enum Empty_bar_bleue  (30/30)

https://www.aldeiarpg.com/

Ir para o topo Ir para baixo

[Lua] Enum Empty Re: [Lua] Enum

Mensagem por Valentine Sex Out 27, 2017 7:45 pm

Nossa! Muito bom, Soreto.

Amo enum I love you

+ 1 crédito
Valentine
Valentine
Administrador
Administrador

Medalhas : [Lua] Enum ZgLkiRU
Mensagens : 5345
Créditos : 1164

https://www.aldeiarpg.com/

Ir para o topo Ir para baixo

Ir para o topo

- Tópicos semelhantes
» Enum

 
Permissões neste sub-fórum
Não podes responder a tópicos