Frage

Ich bin Blei dev für bitfighter , und wir verwenden Lua als Skriptsprache, damit die Spieler programmieren ihre eigene individuell gestaltete Roboter Schiffe.

In Lua, müssen Sie Variablen nicht erklären, und alle Variablen standardmäßig globale Reichweite, sofern nicht anders erklärt. Dies führt zu einigen Problemen. Nehmen Sie den folgenden Code-Schnipsel, zum Beispiel:

loc = bot:getLoc()
items = bot:findItems(ShipType)     -- Find a Ship

minDist = 999999
found = false

for indx, item in ipairs(items) do           
   local d = loc:distSquared(item:getLoc())  

   if(d < minDist) then
      closestItem = item
      minDist = d
   end
end

if(closestItem != nil) then 
   firingAngle = getFiringSolution(closestItem) 
end

In diesem Code-Schnipsel, wenn findItems () keine Kandidaten gibt, dann beziehen sie closestItem noch zu, was Schiff es das letzte Mal gefunden, und in der Zwischenzeit, dass Schiff getötet worden sein könnte. Wenn das Schiff getötet wird, gibt es nicht mehr, und getFiringSolution () fehlschlagen.

Haben Sie das Problem vor Ort? Nun, weder wird meine Nutzer. Es ist subtil, aber mit dramatischem Effekt.

Eine Lösung wäre, zu verlangen, dass alle Variablen deklariert werden, und für alle Variablen zu lokalem Bereich auf Standard. Während diese Änderung unmöglich, es nicht für Programmierer machen würde, um Objekte zu verweisen, die nicht mehr vorhanden ist, würde es erschweren so versehentlich zu tun.

Gibt es eine Möglichkeit Lua zu sagen, alle Vars zu lokalem Bereich auf Default, und / oder zu verlangen, dass sie deklariert werden? Ich weiß, dass einige andere Sprachen (zum Beispiel Perl) haben diese Option zur Verfügung.

Danke!


Es gibt viele gute Antworten hier, danke!

Ich habe beschlossen, mit einer leicht modifizierten Version des Lua ‚strengen‘ Modul zu gehen. Dies scheint mich zu bekommen, wo ich hin will, und ich werde hackt es ein wenig, um die Nachrichten zu verbessern und sie besser geeignet für meinen besonderen Kontext machen.

War es hilfreich?

Lösung

Es gibt keine Möglichkeit, dieses Verhalten zu setzen, aber es ist ein Modul ‚strenge‘ mit der Standard-Installation zur Verfügung gestellt, die genau das tut (durch die Meta-Tabellen zu ändern). Verwendungszweck: erfordern 'strenge'

Für weitergehende Informationen und andere Lösungen: http://lua-users.org/wiki / DetectingUndefinedVariables , aber ich empfehle 'streng'.

Andere Tipps

Sorta.

In Lua, lebt Globals fiktiv in der Globals Tabelle _G (die Wirklichkeit etwas komplexer ist, aber von der Lua Seite gibt es keine Möglichkeit zu sagen, AFAIK). Wie bei allen anderen Lua Tabellen, dann ist es möglich, eine __newindex Metatabelle zu _G anschließen, die steuert, wie Variablen hinzugefügt werden. Lassen Sie diese __newindex Handler tun, was Sie tun wollen, wenn jemand eine globale erstellt. Einen Fehler aus, erlauben es aber eine Warnung drucken, etc

mit _G einzumischen, es ist einfachste und sauberste setfenv zu verwenden. Finden Sie in der Dokumentation rel="nofollow.

"Local ist standardmäßig falsch ". Bitte finden Sie unter

http://lua-users.org/wiki/LocalByDefault

http://lua-users.org/wiki/LuaScopingDiscussion

Sie brauchen eine Art von globalem Umweltschutz zu verwenden. Es gibt einige statischen Werkzeuge, dies zu tun (nicht zu reif), aber die gängigste Lösung ist Runtime-Schutz zu verwenden, basierend auf __index und __newindex in _G der Metatabelle.

Shameles Stecker: Diese Seite kann auch nützlich sein:

http://code.google.com/p/lua-alchemy / wiki / LuaGlobalEnvironmentProtection

Beachten Sie, dass es Lua in swf eingebettet bespricht, die beschriebene Technik (siehe Quellen ) haben für generische Lua arbeiten. Wir verwenden etwas in diese Richtung in unserem Produktionscode bei der Arbeit.

Eigentlich wird die zusätzliche globale Variable mit dem abgestandenen Bezug auf das Schiff ausreichend sein, um die GC zu verhindern, um das Objekt zu verwerfen. So könnte es zur Laufzeit erfasst werden, indem man bemerken, dass das Schiff nun „tot“ ist und sich weigern, etwas damit zu tun. Es ist noch nicht das richtige Schiff, aber zumindest Sie nicht zum Absturz bringen.

Eine Sache, die Sie tun können, ist User-Skripte in einem Sandbox zu halten, wahrscheinlich ein Sandbox pro Skript. Mit der richtigen Manipulation entweder die Umgebungstabelle Sandbox oder seiner Metatabelle, können Sie ordnen alle oder die meisten globalen Variablen aus der Sandbox zu verwerfen, bevor (oder kurz nach) dem Aufruf des Code des Benutzers.

die Sandbox nach Anrufen Aufräumen hätte den Vorteil, verwirft zusätzliche Hinweise auf Dinge, die nicht herumhängen sollten. Dies könnte, indem eine weiße Liste von Feldern durchgeführt werden, die erlaubt sind in der Umgebung zu bleiben und den ganzen Rest zu löschen.

Zum Beispiel folgendes implementiert einen Sandbox-Aufruf an eine vom Benutzer definierte Funktion mit einer Umgebung, nur weiß aufgeführten Namen hinter einer frischen Kratzer Tabelle für jeden Anruf geliefert enthält.

-- table of globals that will available to user scripts
local user_G = {
        print=_G.print,
        math=_G.math,
        -- ...
    }
-- metatable for user sandbox
local env_mt = { __index=user_G }


-- call the function in a sandbox with an environment in which new global 
-- variables can be created and modified but they will be discarded when the 
-- user code completes.
function doUserCode(user_code, ...)
    local env = setmetatable({}, env_mt) -- create a fresh user environment with RO globals
    setfenv(user_code, env)        -- hang it on the user code
    local results = {pcall(user_code, ...)}
    setfenv(user_code,{})
    return unpack(results)
end

Dies könnte erweitert werden, die globale Tabelle schreibgeschützt zu machen, indem sie wieder hinter einem mehr Metatabelle Zugang schieben, wenn man will.

Hinweis

, dass eine vollständige Sandbox-Lösung würde auch überlegen, was über den Benutzer-Code zu tun, die versehentlich (oder böswillig) führt eine unendliche (oder nur sehr lang) Schleife oder einem anderen Betrieb. Allgemeine Lösungen hierfür sind ein gelegentliches Thema der Diskussion über die Lua Liste , aber gute Lösungen sind schwierig.

Lizenziert unter: CC-BY-SA mit Zuschreibung
Nicht verbunden mit StackOverflow
scroll top