Other Languages Moderators Lord Henry Posted March 29, 2023 Other Languages Moderators Share Posted March 29, 2023 (edited) Neste tutorial irei explicar qual a diferença entre um loop usando pairs e um loop usando ipairs. Mas antes de prosseguir, é necessário entender o que é uma tabela indexada e uma tabela não indexada. Tabela indexada é aquela cujos itens tem seu índice declarado. Os índices podem ser números, textos ou elementos. Tabela não indexada é aquela cujos itens não tem seu índice declarado. Porém a linguagem Lua automaticamente indexará essas tabelas com inteiros sequenciais. local tabela = {"1", 2, "três", 0.4, false, 0} -- Tabela não indexada. -- O MTA vai considerar a tabela acima dessa forma: local tabela = { -- Tabela indexada com inteiros sequenciais. [1] = "1", [2] = 2, [3] = "três", [4] = 0.4, [5] = false, [6] = 0 } -- Escrevi a tabela na vertical para facilitar a leitura, não faz diferença escrever tudo na mesma linha. É importante saber disso pois ipairs leva em consideração os índices dos itens de uma tabela, como veremos a seguir. CONCEITO Tanto o pairs quanto o ipairs são utilizados para fazer loops que percorrem uma tabela usando o laço de repetição for. Mas existem situações em que um ipairs não funciona e também há situações em que o pairs não atende ao objetivo que o scripter precisa. Basicamente, o pairs percorre os itens de uma tabela mas não garante a mesma ordem em que eles foram declarados e nem a sequência de seus índices. Sem qualquer ordem específica, ele não exige que a tabela seja indexada por inteiros sequenciais, já que ele não leva em consideração a ordem dos índices da tabela. Enquanto o ipairs (significado: index-value pairs) percorre os itens de uma tabela sempre seguindo a sequência de seus índices. Verificando primeiro o item de índice 1, depois o item de índice 2 e assim por diante. Se um índice da sequência estiver faltando, ele não percorrerá o resto e vai parar de verificar. Também não importa a ordem em que os índices são declarados. Se você declara o item de índice 2 e depois o item de índice 1, mesmo assim ele vai ler o item de índice 1 primeiro e depois o item de índice 2. O ipairs também não é capaz de verificar itens cujo índice não seja um inteiro, pois ele não sabe a sequência que ele pertence, portanto itens de índice string não são verificados pelo ipairs. EXEMPLOS Usando o pairs: (note que o exemplo é server-side, mas tanto o pairs quanto o ipairs podem ser usados client-side também) Server-side addCommandHandler("eae", function(thePlayer, cmd) -- Vamos setar algumas elementDatas em si mesmo só para testes. setElementData(thePlayer, "vida", 100) setElementData(thePlayer, "colete", 90) -- (Datas fictícias, não alteram de verdade a vida nem colete do jogador). setElementData(thePlayer, "vivo", true) setElementData(thePlayer, "procurado", false) setElementData(thePlayer, "emprego", "Mecânico") local datas = getAllElementData(thePlayer) -- Obtém uma tabela com todas as elementDatas do jogador que executou o comando /eae -- A tabela retornada seria assim: (supondo que o jogador não tenha outras elementDatas setadas nele) --[[ local datas = { ["vida"] = 100, ["colete"] = 90, ["vivo"] = true, ["procurado"] = false, -- Este é o único jeito de saber se uma elementData false existe mesmo. ["emprego"] = "Mecânico" } --]] -- Para verificar cada item dessa tabela, o pairs precisa ser usado pois os índices são strings enquanto o ipairs só funciona com índices inteiros sequenciais. for name, value in pairs(datas) do print(name.." = "..tostring(value)) end -- Não há qualquer garantia de que os itens sejam verificados na mesma ordem em que foram declarados. Consideramos isso aleatório. end) Obs: O pairs também funciona em tabelas com índices inteiros sequenciais como o ipairs, porém percorre de maneira aleatória enquanto o ipairs segue a sequência dos índices. 1) Se trocar o pairs por um ipairs, nenhum item será verificado. Pois não foi encontrado o índice 1. Obs2: Mesmo se você definir uma elementData com nome "1", o índice continuará sendo uma string, não sendo lido pelo ipairs. Vimos acima um exemplo que precisa usar pairs pois o ipairs não funcionaria. Agora veremos um exemplo onde o ipairs seria mais adequado. Client-side local palavras = { [1] = "Neste ", [2] = "caso ", [3] = "a ", [4] = "ordem ", [6] = "importa " -- Esqueci do índice 5 de propósito. } local mensagem = "" for i, v in ipairs(palavras) do mensagem = mensagem..v end print(mensagem) Faça os seguintes testes: 1) Execute o código acima do jeito que está, veremos que a mensagem final aparece incompleta. Pois ele não encontrou o índice 5 e parou de verificar o resto dos itens. Retornando a mensagem "Neste caso a ordem " 2) Se trocarmos o ipairs por um pairs, veremos que a mensagem ficará bagunçada, pois os itens foram verificados de maneira aleatória. Porém desta vez todas as palavras serão verificadas, pois o índice não é levado em consideração pelo pairs, somente pelo ipairs. 3) Troque o pairs pelo ipairs de volta e substitua o índice 6 por 5. A mensagem aparecerá completa e com as palavras em ordem. Já que não haverá nenhum índice faltando na sequência. 4) Troque a ordem dos itens da tabela dessa forma: (preste atenção na vírgula, ela é obrigatória em todos os itens, exceto no último) local palavras = { [4] = "ordem ", [2] = "caso ", [5] = "importa ", [1] = "Neste ", [3] = "a " } Veremos que o ipairs continuará verificando cada item na ordem correta. Já que o que importa para ele são os índices e não a ordem em que os itens foram declarados na tabela. Edited March 29, 2023 by Lord Henry Link to comment
Other Languages Moderators Lord Henry Posted March 29, 2023 Author Other Languages Moderators Share Posted March 29, 2023 (edited) CURIOSIDADES Em questão de performance, a diferença entre eles é irrelevante. Mas se considerarmos casos extremos de tabelas gigantes com milhares de itens, a execução do pairs é um pouco mais leve do que ipairs, visto que ele não precisa obedecer ordem nenhuma em sua execução, enquanto que o ipairs precisa sempre verificar a cada execução se o próximo índice existe na tabela inteira. Por esse motivo, se você for obcecado por otimização, prefira usar o pairs. Para saber quantos itens uma tabela possui, geralmente usamos #NomeDaTabela. Mas vale ressaltar que o caractere # na verdade retorna o maior índice conhecido (veremos casos abaixo em que pode existir um índice maior, mas ele não é conhecido). Sendo assim, ele não funciona em tabelas cujos índices não sejam inteiros sequenciais e também retornará a quantidade errada de itens em tabelas que tenham algum índice da sequência faltando. Para contar itens numa tabela de índices aleatórios, usamos uma variável de contador, que vai aumentando em +1 a cada execução do loop e no final nos mostra quantas verificações foram feitas, indicando quantos itens tem na tabela. Vejamos alguns exemplos: local tabela1 = { [4] = "a", [2] = "b", [5] = "c", [1] = "d", [3] = "e" } print("Tabela1: "..#tabela1) -- Retornará 5. Pois é o maior índice conhecido. local tabela2 = { [1] = "a", [2] = "b", [3] = "c", [4] = "d", [6] = "e", } print("Tabela2: "..#tabela2) -- Retornará 6. Mesmo tendo apenas 5 itens, o índice 6 é o maior. local tabela3 = { ["um"] = "a", [22] = "b", ["3"] = "c", [1] = "d", [0] = "e" } print("Tabela3: "..#tabela3) -- Retornará 1. Ele começa a verificar a partir do índice 1, então o índice 0 seria ignorado de qualquer forma. -- Em tabelas que possuem somente índices inteiros, ele iria encontrar o 22. Mas se tiver outros tipos de índices, ele não sabe qual a sequência correta e não verifica os demais. local contador = 0 for _,v in pairs(tabela3) do -- Maneira correta de contar itens numa tabela onde o ipairs não funciona. contador = contador+1 end print("Tabela3 de novo: "..contador) -- Retornará 5. Independente dos índices. Edited March 29, 2023 by Lord Henry Link to comment
Recommended Posts
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 accountSign in
Already have an account? Sign in here.
Sign In Now