Domanda

Ho sentito bombardamenti attorno a Internet per essere in grado di passare a un codice a caldo in LUA in modo simile a come è stato fatto in Java, Erlang, Lisp, ecc. Tuttavia, 30 minuti di Google per questo non hanno scoperto nulla. Qualcuno ha letto qualcosa di sostanziale su questo? Qualcuno ha esperienza di farlo? Funziona in Luajit o solo nella VM di riferimento?

Sono più interessato alla tecnica come scorciatoia nello sviluppo/debug rispetto a un percorso di aggiornamento in un ambiente dal vivo.

È stato utile?

Soluzione

Lua e la maggior parte dei linguaggi di scripting per quella materia, non supportano la forma più generalizzata di "scambiamento a caldo" mentre lo definisci. Cioè non puoi garantevolmente Modificare un file sul disco e avere eventuali modifiche che si propagano in un programma di esecuzione.

Tuttavia, Lua e la maggior parte delle lingue di script per quella materia, sono perfettamente capaci controllato forme di scambio caldo. Le funzioni globali sono funzioni globali. I moduli caricano semplicemente le funzioni globali (se le usi in quel modo). Quindi, se un modulo carica le funzioni globali, è possibile ricaricare nuovamente il modulo se viene modificato e quei riferimenti a funzionalità globali cambieranno nelle funzioni appena caricate.

Tuttavia, Lua e la maggior parte delle lingue di script per quella materia, non ne fanno garanzie. Tutto ciò che sta accadendo è il cambiamento dei dati statali globali. Se qualcuno ha copiato una vecchia funzione in una variabile locale, può comunque accedervi. Se il modulo utilizza i dati sullo stato locale, la nuova versione del modulo non può accedere allo stato del vecchio modulo. Se un modulo crea una sorta di oggetto che ha funzioni membri, a meno che tali membri non vengano recuperati dai globali, questi oggetti si riferiranno sempre alle vecchie funzioni, non a quelle nuove. E così via.

Inoltre, Lua non è sicuro; Non puoi semplicemente interrompere un lua_State Ad un certo punto e prova a caricare di nuovo un modulo. Quindi dovresti impostare un punto specifico nel tempo per controllare le cose e ricaricare i file modificati.

Quindi puoi farlo, ma non è "supportato" nel senso che può accadere. Devi lavorare per questo e devi stare attento a come scrivi le cose e cosa metti nelle funzioni locali e globali.

Altri suggerimenti

Come Nicol disse, la lingua stessa non lo fa per te.

Se vuoi implementare qualcosa del genere da solo, non è così difficile, l'unica cosa che "impedisce" sei qualsiasi riferimento "rimanente" (che indicherà ancora il vecchio codice) e il fatto require cache il suo valore di ritorno in package.loaded.

Il modo in cui lo farei è dividendo il tuo codice in 3 moduli:

  • La logica di ricarica al punto di ingresso (main.lua)
  • Tutti i dati che desideri preservare attraverso RELOADS (data.lua)
  • il codice effettivo da ricaricare (payload.lua), assicurandosi di non conservare alcun riferimento a questo (che a volte non è possibile quando è necessario dare callback a qualche biblioteca; vedi sotto).
-- main.lua:
local PL = require("payload")
local D = require("data")

function reload(module)
  package.loaded[module]=nil -- this makes `require` forget about its cache
  return require(module)
end

PL.setX(5)
PL.setY(10)

PL.printX()
PL.printY()

-- .... somehow detect you want to reload:
print "reloading"
PL = reload("payload") -- make sure you don't keep references to PL elsewhere, e.g. as a function upvalue!

PL.printX()
PL.printY()
-- data.lua:
return {} -- this is a pretty dumb module, it's literally just a table stored in `package.loaded.data` to make sure everyone gets the same instance when requiring it.
-- payload.lua:
local D = require("data")
local y = 0
return {
  setX = function(nx) D.x = nx end, -- using the data module is preserved
  setY = function(ny) y = ny end, -- using a local is reset upon reload
  printX = function() print("x:",D.x) end,
  printY = function() print("y:", y) end
}

produzione:

x: 5
y: 10
reloading
x: 5
y: 0

Potresti arricchire una logica un po 'meglio avendo un "modulo di registro" che tiene traccia di tutto ciò che richiede/ricarichi per te e astratti qualsiasi accesso nei moduli (permettendo così di sostituire i riferimenti) e, utilizzando il __index Metatable in quel registro potresti renderlo praticamente trasparente senza dover chiamare brutti getteri dappertutto. Ciò significa anche che puoi fornire callback "una fodera" che quindi in realtà si basano solo attraverso il registro, se qualche biblioteca di terze parti ne ha bisogno.

Autorizzato sotto: CC-BY-SA insieme a attribuzione
Non affiliato a StackOverflow
scroll top