2016-10-27 4 views
1

Ich versuche, eine Zitat-Funktion in lua, so dass ich die Argumente als Zeichenfolgen, aber ohne Anführungszeichen verwenden oder in einer Umgebung zugreifen kann. Ähnlich wie in der zweiten Kommentar zu this questionZitieren Probleme in Lua

w = print 
function test() 
    local function _ix(_ , k) 
w("    _ix \\ " , _ , k) 
      local v = rawget(_G , k) 
w("    <-- " , k) 
     return k 
     end 
    local _ = setmetatable({} , { __index = _ix }) 
    local function q(_) return _ end 
     q = setfenv(q , _) 
return q 
end 

Also, wenn ich es laufen:

q = test() 
w("q(uno)" , q(uno)) 

Es ist auch nicht die __index metamethod nennen:

---------- Capture Output ---------- 

q(uno) nil 

> Terminated with exit code 0. 

Also, was ich mache ich falsch?

+5

starten durch vernünftige Variablennamen verwenden, Formatierung und weniger selbstinduzierte Indirektion. – Oka

+0

@oka Ich habe einen Schnitt gemacht, der den Code so lesbar gemacht hat, wie ich es erkennen konnte. Sobald es global angewendet wird, sollte es viel einfacher zu lesen sein. – warspyking

+0

@warspyking Ihre Bearbeitung hat eindeutige Konflikte mit dem Originalcode. Sie können das Original wie [this] (https://repl.it/EIW1) umschreiben, aber es ist immer noch unsinnig, da es versucht, Dinge in der falschen Reihenfolge zu suchen. Siehe meine Antwort unten. – Oka

Antwort

0

Wenn ich richtig verstehe, macht das, was du versuchst, nicht viel Sinn. uno wird in der Umgebung nachgeschlagen, die heißt in, nicht mit. In Ihrem Beispiel ist es wie q(nil) anrufen. Das Beispiel aus der anderen Frage funktioniert, weil sie in derselben globalen Umgebung arbeiten.

Sie können eine Hilfsfunktion verwenden schreiben Sie Ihre aktuelle Umgebungen nil -lookups abzufangen, aber es muss präventiv in jeder Umgebung aufgerufen werden wollen Sie diese nil -zu-- string Lookups verwenden.

local function intercept (tab) 
    setfenv(2, setmetatable(tab or {}, { 
     __index = function (_, key) 
      return key 
     end 
    })) 
end 

Und Sie werden eine Umgebung benötigen Funktion Klonen, es sei denn, Sie möchten Ihre Sandkästen jedes Mal manuell erstellen, sonst werden Sie wahrscheinlich vermasseln Mutter Umgebungen (beispielsweise _G). Sie könnten diese Logik innerhalb von intercept für einen saubereren Funktionsaufruf verschieben, aber mit weniger Flexibilität.

local function clone_current_env() 
    local env = {} 

    for key, value in pairs(getfenv(2)) do 
     env[key] = value 
    end 

    return env 
end 

sie zusammen verwenden, können Sie nil Lookups in verursachen Unabhängig davon, welche Umgebung sind Sie in Strings werden.

intercept(clone_current_env()) 
print(type(foo), type(bar)) --> string string 

Dies ist einige hässlich metaprogramming, und ich weiß nicht wirklich, warum Sie Code wie folgt, es sei denn als Proof of Concept schreiben wollen würde.


Ein vollständiges Beispiel.

DEMO

local function clone (tab) 
    local new = {} 

    for key, value in pairs(tab) do 
     new[key] = value 
    end 

    return new 
end 

local function enable_nil_strings() 
    setfenv(2, setmetatable(clone(getfenv(2)), { 
     __index = function (env, key) 
      return key 
     end 
    })) 
end 

local function disable_nil_strings() 
    setmetatable(getfenv(2), nil) 
end 

----------------------------------------------------- 

print(type(foo), type(bar)) --> nil nil 
enable_nil_strings() 
print(type(foo), type(bar)) --> string string 
disable_nil_strings() 
print(type(foo), type(bar)) --> nil nil 

Schließlich wohl der beste Weg, dies zu realisieren wäre einfach um einen Ausführungskontext zu wickeln:

local function with_nil_strings (context, ...) 
    local env = {} 

    for key, value in pairs(getfenv(2)) do 
     env[key] = value 
    end 

    setfenv(
     context, 
     setmetatable(env, { 
      __index = function (_, key) return key end 
     }) 
    ) 

    context(...) 
end 

print(type(foo)) --> nil 

with_nil_strings(function() 
    print(type(foo)) --> string 
end) 

print(type(foo)) --> nil