2009-05-22 9 views
2

nehme ich einen Dateinamen „test.lua“ haben unten enthält Zeilen:Wie bekommt man die Schließung in lua?

--[[ test.lua --]] 
local f = function() 
    print"local function f in test.lua" 
end 

f_generate = function() 
    local fun = loadstring(" f()") 
-- local env = getfenv(1) 
-- set(fun,env) 
    return fun 
end 
f_generate()() 
--[[ end of test.lua--]] 

weil loadString- seine Sachen unter der globalen Umwelt zu tun, so, wenn ich f_generate nennen()() i wird eine Fehlermeldung angezeigt "Versuch, global 'f' (ein Nullwert) aufzurufen"

Der Code auskommentiert zeigt, dass die Funktionsumgebung mit diesem Problem nicht umgehen kann.

Ursache Tabelle ist die einzige Datenstruktur in lua, (und Funktionsumgebung und andere Mengen von Dingen sind durch Tabelle implementieren), ich denke, ist vernünftig anzunehmen, dass die Schließung auch durch Tabelle implementieren, aber wie kann ich es bekommen ?

Antwort

0

Ich glaube, Sie mischen zwei verschiedene Dinge:

  1. Verschlüsse: hierfür ist die Definition von f() innerhalb des Umfangs von was auch immer lokale Variable, die Sie einschließen möchten sein sollte.

    • Einfügen von lokalen Variablen in dynamisch kompilierte Funktionen. Dies wird von Lua nicht offiziell unterstützt. Es ist kein Umweltproblem, es ist eine Bereichssache.

Denken Sie daran: scope lexikalisch ist, während Umwelt ist, was jede Funktion "globaler Raum" hält.

Eine Funktion, die aus einer Textzeichenfolge erstellt wurde, befindet sich in einem anderen lexikalischen Bereich als wäre sie in einer anderen Datei, daher hat sie ihren eigenen Bereich, der von den anderen Funktionen getrennt ist.

BTW, die "Debug" -Schnittstelle lässt Sie mit den lokalen Variablen einer Funktion umgehen, also könnte es einen Weg geben. Ich habe einfach nicht das Bedürfnis, dies zu tun.

0

Sie müssen "lokal" entfernen, sonst wird Müll gesammelt.

--local f = function() 
f = function() 
    print"local function f in test.lua" 
end 
4

Von der Frage gebeten, und der Beispielcode geliefert, ich sehe keine Notwendigkeit für loadstring() verwenden, wenn Funktionen und Schließungen erstklassige Werte in der Sprache sind. Ich würde es so betrachten tun:

 
-- test.lua 
local f = function() 
    print"local function f in test.lua" 
end 

f_generate = function() 
    local fun = function() return f() end 
    return fun 
end 
f_generate()() 
-- end of test.lua 

Die Motivation ist klarer, wenn ein Parameter f_generate ist:

 
-- test.lua 
local f = function(y) 
    print("local function f("..y..") in test.lua") 
end 

f_generate = function(name) 
    local fun = function() return f(name) end 
    return fun 
end 
f_generate("foo")() 
f_generate("bar")() 
-- end of test.lua 

Wenn man durch den Parser mit loadstring() nimmt explizit den Code außerhalb des Geltungsbereichs des Anrufs zu loadstring(). Lokale Variablen werden nicht in einer Umgebungstabelle gespeichert. Sie werden ähnlich wie in jeder anderen Sprache implementiert: Der Speicher für sie wird vom Codegenerator zugewiesen und ist außerhalb dieser Kompilierung nicht zugänglich. Natürlich hat das Debug-Modul (und die API) die Möglichkeit, einen Blick darauf zu werfen, aber das wird nie für die Verwendung außerhalb eines Debuggers empfohlen.

Die korrekte Methode, einen Verweis auf ein lokales Dokument für die Verwendung außerhalb des Gültigkeitsbereichs beizubehalten, ist ein echter Upvalue für einen Abschluss. Das wird erreicht durch fun = function() return f() end. In diesem Fall wird der Wert f als Upvalue für die in fun gespeicherte Funktion beibehalten.Beachten Sie, dass in der Praxis dieses Wrapping als Upvalue sehr effizient ist. Um den Wert zu finden, ist kein Name-Lookup erforderlich, und da ich einen Tail-Call verwende, sind auch keine zusätzlichen Stack-Frames erforderlich.

+0

lokal __cmp__table = { [ ">"] = Funktion (a, b) liefert ein> b Ende, [ "> ="] = Funktion (a, b) liefern ein> = b Ende, [ "<"] = Funktion (a, b) liefern eine gray

+0

das ist der echte code, es scheint, dass ich wirklich loadstring brauchen, jede suggustion? und beiseite legen alle praktischen Notwendigkeit und Workaround, können wir immer noch über die Fähigkeit, die Schließung zu bekommen, schließlich ist die Schließung die aktive Datensatzkette der Funktion (korrigieren Sie mich, wenn ...), und ich denke, lua implementieren es als Tabelle (denn alles Ding kann als Tabelle implementieren ...; wieder, korrigieren Sie mich, wenn ...) vielen Dank, es hilft wirklich. – gray

+0

@gray: Nein, Closures und lokale variable Frames sind keine Tabellen. – Javier

0

Sehen Sie, Sie können keine Funktionen/Verschlüsse als Tabellen behandeln. Betrachten Sie den folgenden Code:

local table = { 
    baz = { 
     blah = "bar" 
    }, 
    foo = table.baz.blah 
} 

In diesem Fall führen Sie das Äquivalent von Zugriff auf etwas in einem engeren Umfang aus einem größeren Bereich. Dies ist mit Funktionen nicht möglich. Wenn dies zutrifft, können Sie auf lokale Variablen zugreifen, die Sie normalerweise nicht verwenden können.

Nun Festsetzung Code:

local __cmp__table = { 
    [">"] = function(a,b) return a>b end, 
    [">="] = function(a,b) return a>=b end, 
    ["<"] = function(a,b) return a<b end, 
    ["<="] = function(a,b) return a<=b end, 
    ["=="] = function(a,b) return a==b end, 
    ["~="] = function(a,b) return a~=b end, 
} 
cmp = function(a, op, b) 
    return __cmp__table[op](a,b) 
end 

Dies ermöglicht es Ihnen cmp auf zwei beliebigen Variablen mit der richtigen Vergleichsfunktion aufzurufen. Wenn ich den Punkt über Ihren Code verpasst habe, dann sagen Sie es mir bitte!