Skip to content

TkzDev/Dicas-Lua-Otimizacao

 
 

Folders and files

NameName
Last commit message
Last commit date

Latest commit

 

History

2 Commits
 
 

Repository files navigation


Lua: Dicas de Otimização

Lua

Lua é conhecida por ser uma linguagem de alto desempenho em muitos cenários, especialmente em sistemas embarcados, jogos e aplicativos de tempo real. No entanto, como qualquer linguagem de programação, ela tem seus pontos fortes e limitações em relação ao desempenho. Aqui estão alguns pontos positivos e negativos em relação ao desempenho em Lua:

Pontos Positivos:

  1. Linguagem de Script Eficiente: Lua é uma linguagem de script de alto desempenho, projetada para ser rápida e eficiente na execução de código interpretado. Ela possui um mecanismo de execução de bytecode eficaz.

  2. Baixo Overhead: Lua tem um baixo overhead de memória e recursos, o que a torna adequada para sistemas com restrições de memória e processamento, como sistemas embarcados.

  3. Extensibilidade: É possível estender Lua com código C/C++ para otimizar partes críticas de um programa. Lua fornece uma API C para integração fácil.

  4. Garbage Collector Configurável: Lua oferece a capacidade de configurar e ajustar o coletor de lixo de acordo com os requisitos de desempenho do aplicativo. Isso pode ser útil para evitar picos de uso de memória em tempo real.

  5. Gerenciamento de Memória Eficiente: O coletor de lixo automático em Lua é projetado para ser eficiente, minimizando a interrupção do programa e liberando memória de forma inteligente.

Pontos Negativos:

  1. Interpretação vs. Compilação: Como uma linguagem interpretada, Lua tende a ser mais lenta do que linguagens compiladas em certos cenários. Isso pode ser um fator limitante em aplicativos que exigem um desempenho extremamente alto.

  2. Limitações de Multithreading: Lua não lida muito bem com programação concorrente e multithreading, o que pode ser uma desvantagem em aplicativos que exigem alta concorrência e paralelismo.

  3. Falta de Tipagem Estática: A tipagem dinâmica em Lua pode resultar em perda de desempenho, já que o interpretador precisa fazer verificação de tipos em tempo de execução. Isso pode ser um problema em algoritmos altamente otimizados.

  4. Bibliotecas Não Nativas: Lua não possui muitas bibliotecas nativas de alto desempenho para tarefas específicas. Dependendo do caso, pode ser necessário recorrer a bibliotecas em C/C++ para obter o desempenho desejado.

Em resumo, Lua é uma linguagem de alto desempenho em muitos cenários, especialmente quando se trata de sistemas embarcados, jogos e scripts de automação. No entanto, é importante entender suas limitações, como a falta de suporte nativo a multithreading e a tipagem dinâmica, ao avaliar se é a escolha certa para um projeto que exige desempenho extremamente alto. Em muitos casos, é possível obter um equilíbrio entre desempenho e facilidade de desenvolvimento usando Lua de forma eficaz.

Gerenciamento de Memória em Lua

O gerenciamento de memória em Lua é uma característica fundamental da linguagem que contribui para a sua produtividade e confiabilidade. Neste documento, explicaremos como o sistema de gerenciamento de memória em Lua funciona em detalhes.

Controle de Referências

Em Lua, todas as variáveis (exceto nil) são referências a objetos na memória. Isso significa que as variáveis não armazenam diretamente o valor, mas uma referência ao valor. Por exemplo, quando você faz a = 10, a se torna uma referência para o valor 10 na memória.

Alocação de Memória

Sempre que você cria um novo objeto (como uma tabela, uma string ou uma função), o Lua aloca memória para armazenar esse objeto. Isso é feito de forma automática e transparente para o programador.

Coletor de Lixo

O coletor de lixo é responsável por monitorar e recuperar a memória que não está mais em uso. Ele faz isso identificando objetos que não podem mais ser acessados pelo programa e liberando a memória ocupada por esses objetos.

Marcadores de Referência

O coletor de lixo usa marcadores de referência para determinar quais objetos estão em uso. Ele começa a partir de um conjunto de objetos conhecidos como "raízes" (como variáveis globais, tabelas globais, etc.) e, a partir daí, segue as referências para outros objetos.

Contagem de Referências

O coletor de lixo utiliza a contagem de referências para acompanhar quantas referências existem para um objeto específico. Se um objeto não tiver nenhuma referência, ele é considerado inacessível e pode ser coletado pelo coletor de lixo.

Ciclos de Referência

O coletor de lixo é capaz de lidar com ciclos de referência, que ocorrem quando dois ou mais objetos se referenciam mutuamente, mas não são acessíveis a partir de raízes. O coletor de lixo detecta esses ciclos e os coleta quando não estão mais acessíveis.

Limpeza e Recuperação de Memória

Quando o coletor de lixo determina que um objeto não é mais acessível, ele desaloca a memória ocupada por esse objeto e a devolve ao sistema operacional, tornando-a disponível para alocações futuras.

Pontos Importantes a Serem Observados

  • O coletor de lixo em Lua é executado de forma assíncrona e periódica. Isso significa que não há garantia de quando exatamente a memória será liberada, o que pode levar a picos de uso de memória em alguns casos.

  • O coletor de lixo é altamente configurável em Lua. Você pode ajustar parâmetros para controlar a frequência e o comportamento do coletor de lixo, embora isso não seja geralmente necessário na maioria dos casos.

  • O gerenciamento de memória em Lua é transparente para o programador, o que significa que você não precisa se preocupar com a alocação ou liberação de memória manualmente, a menos que esteja lidando com extensões em C/C++ para Lua.

Em resumo, o gerenciamento de memória em Lua é uma parte fundamental da linguagem que torna a programação mais conveniente e segura, ao mesmo tempo em que alivia os programadores da responsabilidade de lidar diretamente com a alocação e liberação de memória. Isso contribui para a produtividade e a confiabilidade do código escrito em Lua.

ATENÇÃO

Essas técnicas abaixo podem ajudar a otimizar seu código em cenários específicos. No entanto, a regra geral de otimização ainda se aplica: primeiro, escreva código limpo e compreensível; depois, identifique os gargalos de desempenho usando ferramentas de profiling apropriadas e, finalmente, aplique otimizações direcionadas para resolver esses gargalos específicos. E sempre teste para garantir que as otimizações realmente melhoram o desempenho sem introduzir bugs.

Collectgarbage como usar

A função collectgarbage() em Lua é usada para controlar o coletor de lixo da linguagem. O coletor de lixo é um mecanismo interno que libera memória ocupada por objetos (como tabelas, funções, userdata, etc.) que não são mais acessíveis ou necessários. Isso é crucial em qualquer linguagem de programação, pois gerencia a memória automaticamente, prevenindo vazamentos de memória e outros problemas.

Usos da função collectgarbage()

A função collectgarbage() pode ser usada de várias maneiras, dependendo do argumento que você passa para ela. Aqui estão alguns exemplos:

1. collectgarbage("collect")

  • Executa uma coleta de lixo completa.
    collectgarbage("collect")
    Use esse comando com cuidado, pois forçar uma coleta completa de lixo pode causar uma pausa perceptível no seu programa, especialmente se houver muita memória para coletar.

2. collectgarbage("count")

  • Retorna a quantidade de memória (em Kbytes) em uso pelo Lua.
    local memoryUsed = collectgarbage("count")
    print("Memória usada:", memoryUsed, "KB")
    Isso é útil para monitorar o uso de memória do seu aplicativo.

3. collectgarbage("stop")

  • Interrompe o coletor de lixo.
    collectgarbage("stop")
    Você pode querer fazer isso se souber que está prestes a fazer muitas alocações de memória e quiser evitar pausas de coleta de lixo.

4. collectgarbage("restart")

  • Reinicia o coletor de lixo.
    collectgarbage("restart")
    Se você parou o coletor de lixo anteriormente, use isso para reiniciá-lo.

5. collectgarbage("step")

  • Executa uma etapa do coletor de lixo, o tamanho da etapa é controlado pelo parâmetro opcional (um número inteiro).
    collectgarbage("step", 1024)
    Isso pode ser útil para evitar longas pausas de coleta de lixo, fazendo a coleta de lixo em etapas menores ao longo do tempo.

6. collectgarbage("setpause")

  • Define o valor da pausa do coletor de lixo.
    collectgarbage("setpause", 110)
    A "pausa" é o tempo que o coletor de lixo espera antes de iniciar uma nova coleta após concluir a última. É expressa em porcentagem.

7. collectgarbage("setstepmul")

  • Define o valor do "step multiplier".
    collectgarbage("setstepmul", 200)
    O "step multiplier" controla a velocidade da coleta de lixo em relação à alocação de memória.
  1. collectgarbage("isrunning")
  • Retorna um booleano que indica se o coletor de lixo está em execução (não parado).
    local isRunning = collectgarbage("isrunning")
    print("O coletor de lixo está em execução?", isRunning)
    Útil para verificações de estado.
  1. Conclusão

Esses exemplos demonstram como você pode interagir e controlar o coletor de lixo em Lua. Isso pode ser muito útil em ambientes com restrição de memória ou para otimizar o desempenho em aplicações que fazem uso intensivo de memória. Contudo, a maioria dos programas não precisa interagir diretamente com o coletor de lixo, pois Lua é projetada para gerenciar a memória de maneira eficiente sem intervenção manual.

Dicas de otimização

Otimizar o código em Lua envolve várias técnicas, dependendo do contexto específico e das exigências do seu projeto. Aqui estão algumas dicas gerais:

  1. Uso local de variáveis: Variáveis locais em Lua são acessadas mais rapidamente do que as globais. Sempre que possível, use variáveis locais.

    local x = 10 -- mais rápido
    x = 10 -- mais lento (global)
  2. Evitar funções desnecessárias: Funções em Lua têm um custo de overhead. Se uma função faz algo extremamente simples, pode ser mais eficiente fazer essa operação diretamente, especialmente dentro de loops.

    -- Em vez de:
    function add(a, b) return a + b end
    total = add(5, 10) -- chamada de função
    
    -- Use:
    total = 5 + 10 -- operação direta
  3. Otimização de laços: Em Lua, o uso de pairs ou ipairs em laços é menos eficiente do que o laço numérico padrão. Quando possível, use um laço for com um contador.

    -- Em vez de:
    for i, v in ipairs(myTable) do 
      -- código
    end
    
    -- Use:
    for i=1, #myTable do
      local v = myTable[i]
      -- código
    end
  4. Hashmaps: Em Lua, as tabelas já funcionam como hashmaps, o que permite acessos muito rápidos a dados não sequenciais. Isso é especialmente útil quando você tem grandes quantidades de dados e precisa de acesso rápido a itens específicos sem percorrer toda a estrutura de dados. Abaixo está um exemplo demonstrando o uso de uma tabela como hashmap para otimização e uma comparação de tempo de execução com uma abordagem baseada em lista.

    local os = require("os")
    
    -- Utilizando lista (array)
    local lista = {}
    for i = 1, 1000000 do
        lista[i] = {chave = "chave"..i, valor = "valor"..i}
    end
    
    -- Utilizando hashmap
    local hashmap = {}
    for i = 1, 1000000 do
        hashmap["chave"..i] = "valor"..i
    end
    
    -- Busca na lista (ineficiente)
    local tempoInicioLista = os.clock()
    for i = 1, #lista do
        if lista[i].chave == "chave500000" then
            print("Encontrado na lista: " .. lista[i].valor)
            break
        end
    end
    local tempoFimLista = os.clock()
    
    -- Busca no hashmap (eficiente)
    local tempoInicioHashmap = os.clock()
    print("Encontrado no hashmap: " .. hashmap["chave500000"])
    local tempoFimHashmap = os.clock()
    
    -- Medindo a diferença de tempo
    print("Tempo com lista: ", tempoFimLista - tempoInicioLista)
    print("Tempo com hashmap: ", tempoFimHashmap - tempoInicioHashmap)

Neste exemplo, primeiro preenchemos uma lista e um hashmap com um milhão de entradas. Em seguida, tentamos buscar um item no meio da estrutura de dados.

  • Com a lista, temos que percorrer cada elemento até encontrar o que estamos procurando. Isso é O(n) na notação Big O, onde "n" é o número de elementos na lista, porque, no pior dos casos, teríamos que percorrer toda a lista.
  • Com o hashmap, o acesso é quase instantâneo, independentemente do tamanho da tabela, porque não depende do número de elementos na tabela. Isso é O(1) na notação Big O, o que significa que o tempo de acesso é constante, não importa o quão grande o hashmap se torne.

Você verá uma diferença significativa no tempo de execução, demonstrando a eficiência de usar hashmaps para acesso rápido a grandes conjuntos de dados.

  1. Tabelas e alocação de memória: Reutilizar tabelas em vez de criar novas é uma prática recomendada. A alocação de memória (como a criação de tabelas) é uma operação cara. Se você precisa de tabelas temporárias em um loop, considere criar uma fora do loop e reutilizá-la.

    local t = {}  -- reutilização de tabela
    for i=1, 1000 do
      -- limpa a tabela
      for k in pairs(t) do t[k] = nil end
    
      -- usa a tabela 't'
    end
  2. Concatenação de strings: O operador de concatenação (..) em Lua pode ser caro se usado repetidamente, como em um loop. Se você estiver concatenando muitas strings, considere usar a função table.concat.

    local strings = {"Hello", "Lua", "World"}
    local result = table.concat(strings, " ")  -- Mais eficiente
  3. Usar métodos embutidos quando possível: Funções de biblioteca embutidas geralmente são mais otimizadas do que código Lua equivalente.

  4. Evitar closures desnecessários: Closures são úteis e poderosos, mas cada closure é um novo objeto que consome memória. Se não precisar de um closure, use uma função regular ou local.

    -- Em vez de:
    function outer()
      local function inner() -- closure que poderia ser evitado
        -- código
      end
      inner()
    end
    
    -- Use:
    local function inner() -- função local regular
      -- código
    end
    
    function outer()
      inner()
    end
  5. Reduzir o uso de metatables: Metatables permitem que você defina comportamentos customizados para tabelas, mas usar metatables pode reduzir a performance, especialmente se acessadas dentro de loops intensivos. Se possível, use tabelas regulares e funções.

  6. Usar table.insert com cautela: table.insert é útil, mas pode ser mais lento do que simplesmente definir valores diretamente em índices de tabela, especialmente em loops.

    local myTable = {}
    for i=1, 1000 do
      myTable[#myTable+1] = i -- mais rápido que table.insert
    end
  7. Otimizar condições de if-else: Tente organizar suas declarações if-else de maneira que os casos mais prováveis sejam testados primeiro.

  8. Evitar chamadas de função em condições de loop: Se uma chamada de função retorna um valor que não muda durante o loop, chame-a fora do loop.

    -- Em vez de:
    for i=1, 1000 do
      if i < someFunction() then -- someFunction é chamada 1000 vezes
        -- código
      end
    end
    
    -- Use:
    local threshold = someFunction() -- chamada uma vez
    for i=1, 1000 do
      if i < threshold then
        -- código
      end
    end
  9. Reduzir o escopo das variáveis: Mantenha o escopo das variáveis o mais restrito possível para melhorar a legibilidade e reduzir a chance de alterações indesejadas no estado do programa.

    -- Em vez de:
    function doSomething()
      x = 10 -- global, poderia ser alterado em qualquer lugar
      -- código
    end
    
    -- Use:
    function doSomething()
      local x = 10 -- local, só existe dentro desta função
      -- código
    end
  10. Pré-calcular valores: Se você tem cálculos que sempre resultam no mesmo valor, considere pré-calcular esses valores e armazená-los, ao invés de calcular repetidamente.

    local valores = {}
    local CONSTANTE = math.sqrt(2) / 2  -- Um valor que não muda
    
    for i = 1, 1000000 do
        valores[i] = i * CONSTANTE
    end
  11. Otimização de funções matemáticas: Funções matemáticas nativas são geralmente mais rápidas do que as implementadas em Lua. Por exemplo, usar math.sin() em vez de uma versão personalizada em Lua.

  12. Usar operadores bitwise onde possível: Em operações que podem ser feitas com operadores bitwise, como checar se um número é par (usando bitwise AND para verificar o último bit), eles podem oferecer melhor performance em comparação com operações aritméticas regulares.

    function is_even(num)
        return (num & 1) == 0
    end
    
    -- Testando a função com alguns números
    local test_numbers = {1, 2, 3, 4, 5, 6}
    for i, number in ipairs(test_numbers) do
        if is_even(number) then
            print(number .. " é par.")
        else
            print(number .. " é ímpar.")
        end
    end
  13. Reciclagem de objetos: Em vez de criar novos objetos (como tabelas ou strings) em um loop, reutilize-os. Isso é conhecido como "object pooling" e é útil para evitar a alocação frequente de memória, que é uma operação custosa.

    local bullet = {} -- reutilizando objeto
    for i=1, 100 do
      bullet.x = i
      bullet.y = i*2
      -- código
    end
  14. Reduzir o uso do coletor de lixo: O coletor de lixo pode causar pausas perceptíveis na execução do programa. Reduzir a criação de lixo (por exemplo, evitando criar muitos objetos temporários) pode ajudar. Além disso, você pode controlar o coletor de lixo com collectgarbage(), mas use com cautela. ``

  15. Evitar tabelas dinâmicas: Se você souber o tamanho da tabela, pré-defina o tamanho. Tabelas que mudam de tamanho frequentemente podem levar a re-hashing, que é custoso.

    local fixedSizeTable = {0, 0, 0, 0, 0} -- tamanho de tabela pré-definido
  16. Usar string.byte para comparações de caracteres únicos: Se você está apenas verificando um caracter, string.byte é mais rápido que string.sub. Útil em parsers ou processamento de texto.

    if string.byte(str, i) == 97 then -- compara com o código ASCII de 'a'
      -- código
    end
  17. Pré-compile seu código: Se você está executando um script Lua muitas vezes, pode ser útil pré-compilar o script para bytecode usando string.dump. Isso remove a necessidade de análise sintática do código-fonte.

  18. Usar contagem de referência para grandes estruturas de dados: Se você tem grandes estruturas de dados que são imutáveis, use contagem de referência para compartilhá-las entre as funções, em vez de copiá-las.

  19. Usar bibliotecas de C se necessário: Para tarefas muito intensivas em termos de CPU, você pode escrever uma extensão em C e chamá-la de Lua. As extensões em C podem ser significativamente mais rápidas para certas tarefas.

  20. Evitar double dispatch: Double dispatch é um cenário em que você faz duas chamadas de função onde uma poderia ser suficiente. Isso ocorre comumente com metatables e métodos de objeto.

    -- Em vez de:
    obj:method() -- Isso é uma chamada disfarçada para obj.metatable:method(obj)
    
    -- Se possível, use:
    method(obj)
  21. Usar o operador length com cuidado: Em Lua, o operador # para obter o comprimento de uma tabela pode ser lento em tabelas não sequenciais, pois ele tenta calcular o comprimento ao invés de acessá-lo diretamente. Se você mantiver o controle do tamanho da tabela, isso pode ser mais rápido.

    local size = 0
    local myTable = {}
    
    -- ao adicionar à tabela
    myTable[#myTable+1] = value
    size = size + 1
  22. Lazy loading: Se seu programa tem módulos ou dados que não são sempre utilizados, considere usar o carregamento preguiçoso (lazy loading), onde você só carrega/captura os dados quando eles são necessários.

    local function loadData()
      data = data or heavyDataLoadingFunction()  -- só carrega quando necessário
      return data
    end
  23. Reduzir o número de chamadas de função indiretas: Funções chamadas através de tabelas (como métodos de objetos) são ligeiramente mais lentas do que chamadas de função direta ou local.

    -- Direto e mais rápido
    local function foo() end
    foo()
    
    -- Indireto e um pouco mais lento
    local t = {foo = function() end}
    t.foo()
  24. Usar técnicas de memoização: Se você tem funções que são chamadas frequentemente com os mesmos argumentos, e elas são puras (retornam o mesmo resultado para os mesmos argumentos), você pode usar memoização para guardar os resultados anteriores e retorná-los para chamadas futuras.

    local function expensiveFunction(x)
      -- código caro...
    end
    
    local memo = {}
    local function memoizedExpensiveFunction(x)
      if memo[x] then return memo[x] end
      memo[x] = expensiveFunction(x)
      return memo[x]
    end
  25. Flattening de tabelas: Se você frequentemente acessa itens em tabelas aninhadas, pode ser mais rápido "achatar" as tabelas em uma única tabela de nível superior com chaves compostas, para reduzir o custo de acesso.

    function flatten(t)
        local flatTable = {}
        local function flattenHelper(t)
        for _, v in ipairs(t) do
            if type(v) == "table" then
                flattenHelper(v)
            else
                table.insert(flatTable, v)
            end
        end
    
        flattenHelper(t)
        return flatTable
    end
    
    -- Exemplo de uso
    local nestedTable = {1, 2, {3, 4, {5, 6}, 7}, 8, {9}}
    local flatTable = flatten(nestedTable)
    
    for _, v in ipairs(flatTable) do
        print(v)
    end
  26. Otimizar a inicialização de aplicativos Lua: Se seu aplicativo precisa inicializar muitos dados ou estado na inicialização, considere formas de otimizar esse processo, talvez movendo a inicialização para um thread em segundo plano ou salvando/capturando estado entre as execuções.

  27. Manter o código Lua simples: Embora possa parecer contra-intuitivo, tentar ser "inteligente" com o código às vezes pode torná-lo mais lento. Lua é mais rápida com código simples e direto.

  28. Batching de operações de rede ou IO: Se o seu código Lua está fazendo operações de entrada/saída (IO) ou chamadas de rede, fazer essas operações em lote (batch) pode ser mais eficiente do que fazer muitas operações individuais.

    local messages = {}
    -- Adiciona mensagens a uma fila em vez de enviá-las imediatamente
    function queueMessage(message)
        table.insert(messages, message)
    end
    
    -- Envia mensagens em lote
    function sendMessages()
        network.sendBatch(messages) -- função hipotética
        messages = {} -- limpa a fila
    end
  29. Desenrolar loops (Loop unrolling): Se você tem um loop com um número pequeno e fixo de iterações, pode ser mais rápido 'desenrolar' o loop.

    -- Em vez de:
    for i=1, 4 do
        doSomething(i)
    end
    
    -- Use:
    doSomething(1)
    doSomething(2)
    doSomething(3)
    doSomething(4)
  30. Usar corrotinas para tarefas longas: Se você tem operações que levam muito tempo e estão fazendo seu programa travar, considere usar corrotinas para dividir o trabalho em pedaços menores que cedem o controle de volta ao evento principal entre as execuções.

    local function doLongTask()
        -- faz parte do trabalho
        coroutine.yield()
        -- faz mais trabalho
    end
    
    local co = coroutine.create(doLongTask)
    
    -- em algum lugar no loop principal do seu programa
    coroutine.resume(co)
  31. Evitar padrões de design complexos para tarefas simples: Padrões de design são poderosos, mas podem introduzir overhead desnecessário se usados indevidamente. Para tarefas simples, um código direto pode ser mais eficiente.

  32. Fusão de loop (Loop fusion): Se você tem múltiplos loops percorrendo a mesma tabela sequencialmente, pode ser mais eficiente fundir esses loops em um só.

    -- Em vez de:
    for i=1, #t do
        process1(t[i])
    end
    
    for i=1, #t do
        process2(t[i])
    end
    
    -- Use:
    for i=1, #t do
        process1(t[i])
        process2(t[i])
    end
  33. Inicialização de tabela eficiente: Quando você sabe quais campos uma tabela terá, inicialize-a com todos os campos de uma só vez, em vez de adicioná-los um por um. Isso pode ajudar o compilador a otimizar o código.

    -- Em vez de:
    local player = {}
    player.name = "John"
    player.score = 0
    
    -- Use:
    local player = {name = "John", score = 0}
  34. Aproveitar o tail call optimization (TCO): Lua suporta a "otimização de chamadas de cauda", o que significa que funções recursivas escritas de certa forma (onde a última ação é chamar a própria função) não aumentam a pilha de chamadas, tornando-as mais eficientes.

    local function factorial(n, acc)
        acc = acc or 1
        if n <= 1 then return acc end
        return factorial(n - 1, n * acc) -- exemplo de chamada de cauda
    end
  35. Evitar métodos desnecessários em strings e números: Métodos em strings e números em Lua são convenientes, mas geralmente mais lentos do que funções independentes do módulo string ou math.

    local s = "example"
    -- Em vez de s:upper(), use:
    local upper = string.upper(s)
  36. Reduzir condições em loops: Se você tem um if dentro de um loop que verifica uma condição que não muda durante o loop, verifique-a fora do loop.

    if condition then
        for i=1, #items do
            -- código que só executa se 'condition' for verdadeiro
        end
    end
  37. Minimizar o escopo de variáveis locais: Quanto menor o escopo de uma variável local, mais fácil é para a Lua gerenciar a memória e o ciclo de vida dessa variável, o que pode levar a um código mais eficiente.

    do
        local temp = computeValue()  -- 'temp' está limitado a este bloco
        -- use 'temp'
    end
    -- mais código onde 'temp' não é acessível
  38. Armazenar funções usadas repetidamente em variáveis locais: Se uma função é usada várias vezes, especialmente dentro de um loop, armazená-la em uma variável local pode reduzir a sobrecarga de procurar essa função no escopo global ou em tabelas.

    local floor = math.floor
    -- Agora 'floor' pode ser usado diretamente

About

No description, website, or topics provided.

Resources

Stars

Watchers

Forks

Releases

No releases published

Packages

No packages published