Ich denke, was verwirrt Sie ist die proper tail call Funktion von Lua.
Um dies zu verstehen, ändern wir Ihre locals
Funktion, so dass es ein Argument als Level-Stack akzeptiert in Aufruf an debug.getlocal
. (Ich bin mit Lua 5.3.3)
-- Get local variables with stack level 'level'.
function locals(level)
local variables = {}
local idx = 1
while true do
local ln, lv = debug.getlocal(level, idx)
if ln ~= nil then
variables[ln] = lv
else
break
end
idx = 1 + idx
end
return variables
end
Dann wir Ihre Testfunktionen ändern, das Hinzufügen das gleiche Argument, und fügen Sie eine test3
Funktion als Referenz.
function test1(level)
local v = 'I am a local!'
return locals(level)
end
function test2(level)
local v = 'I am a local!'
return (locals(level))
end
function test3(level)
local v = 'I am a local!'
local a = locals(level)
return a
end
Schließlich fügen wir etwas Code hinzu, um die Tests durchzuführen.
Der obige Code führt die Testfunktionen mit verschiedenen Stack-Ebenen aus und gibt die zurückgegebenen Schlüssel/Wert-Paare aus. Mein Ergebnis ist wie folgt:
==== Stack level: 1
What test1 returns:
key = variables, val = table: 0x7fa14bc081e0.
key = idx, val = 3.
key = level, val = 1.
What test2 returns:
key = variables, val = table: 0x7fa14bc08220.
key = idx, val = 3.
key = level, val = 1.
What test3 returns:
key = variables, val = table: 0x7fa14bc088b0.
key = idx, val = 3.
key = level, val = 1.
==== Stack level: 2
What test1 returns:
key = (for step), val = 1.
key = (for limit), val = 3.
key = (for index), val = 1.
key = level, val = 2.
key = printTable, val = function: 0x7fa14bc08360.
key = (*temporary), val = function: 0x7fa14bc08360.
key = num, val = 1.
What test2 returns:
key = level, val = 2.
key = v, val = I am a local!.
What test3 returns:
key = level, val = 2.
key = v, val = I am a local!.
==== Stack level: 3
What test1 returns:
key = (*temporary), val = function: 0x109f5a070.
What test2 returns:
key = (for step), val = 1.
key = (for limit), val = 3.
key = (for index), val = 2.
key = level, val = 3.
key = printTable, val = function: 0x7fa14bc08360.
key = (*temporary), val = function: 0x7fa14bc08360.
key = num, val = 2.
What test3 returns:
key = (for step), val = 1.
key = (for limit), val = 3.
key = (for index), val = 3.
key = level, val = 3.
key = printTable, val = function: 0x7fa14bc08360.
key = (*temporary), val = function: 0x7fa14bc08360.
key = num, val = 3.
Wenn level
1, locals
funktioniert gut seine eigene lokale Variablen zu geben. Aber wenn level
2 ist, gibt test1
Variablen des äußeren Bereichs zurück, während test2
und test3
das Ergebnis ergeben, das Sie erwarten. Für Stack-Level 3 test2
und test3
zurück etwas wie test1
auf Stack-Ebene 2. So scheint es test1
springt ein Stack-Level, und die einzige Erklärung, die ich denken könnte, ist die richtige Tail Call.
Nach PIL (der Link, den ich am Anfang), ein richtiger Tail-Call wird nie dazu führen, dass der Stapel überlaufen, die ich als den Anruf in einigen inline Weg nehmen. Wenn ich damit recht habe, erklärt dies das Überspringungsverhalten der Return-Anweisung test1
, denn das ist ein richtiger Tail-Call und der einzige in den 3 Testfunktionen.
Ich liebe Ihre Methodik! Ich danke dir sehr. – yawn
Ich bin mir nicht sicher, wie man Code in Kommentaren schreibt, aber es scheint tatsächlich über Tail Calls zu sein, da das Wrapping von Locals (2) mit einer Identity Funktion funktioniert, die, wie in Schema vorausgesetzt, ausreichen sollte Tail-Call-Optimierung. Ich nehme an, dass, da Klammern in Lua irgendeine Form der Berechnung ausführen (nur den ersten von mehreren Werten zurückgeben), sie ausreichend gewesen sein müssen, um den TCO zu deaktivieren – yawn