2016-11-28 36 views
2

就像我們如何能做到這一點:有沒有一個表可以用來訪問Lua中的局部變量?

a = 3 
print(_G['a']) -- 3 

我希望能夠做這樣的事情:

local a = 3 
print(_L['a']) -- 3 

我基本上希望能夠用自己的名字來訪問本地變量爲字符串。有沒有一個表可以做到這一點,也許可以作爲函數參數傳遞?這就像ActionScript中的this關鍵字。

+1

請避免這樣做。我知道它可能看起來很刺耳,但通常有更好的方法來做你想在Lua中做的事情,而不是使用調試庫。請避免[XY問題](http://meta.stackexchange。com/questions/66377/what-the-xy-problem) – ATaco

+0

http://hawwashsoft.proboards.com/thread/64/locals – warspyking

回答

3

這可以通過debug庫的方式 - 即getlocalsetlocal功能。如果你不能使用這個庫(或訪問C API),那麼你運氣不好。

您可以使用特製的_L表擴展您的全球環境,該表在訪問時執行當前一組當地人的線性查找。

讀取局部變量只是找到一個匹配的變量名,並返回它的值。寫入本地變量需要您在堆棧框架中發現其索引,然後相應地更新該值。請注意,您不能創建新的當地人。

下面是一個簡單的例子,適用於Lua 5.1(但不是Lua 5.2+)。

local function find_local (key) 
    local n = 1 
    local name, sname, sn, value 

    repeat 
     name, value = debug.getlocal(3, n) 

     if name == key then 
      sname = name 
      sn = n 
     end 

     n = n + 1 
    until not name 

    return sname, sn 
end 

_G._L = setmetatable({}, { 
    metatable = false, 
    __newindex = function (self, key, value) 
     local _, index = find_local(key) 

     if not index then 
      error(('local %q does not exist.'):format(key)) 
     end 

     debug.setlocal(2, index, value) 
    end, 
    __index = function (_, key) 
     return find_local(key) 
    end 
}) 

在使用中:

local foo = 'bar' 

print(_L['foo']) --> 'bar' 
_L['foo'] = 'qux' 
print(_L['foo']) --> 'qux' 

local function alter_inside (key) 
    local a, b, c = 5, 6, 7 
    _L[key] = 11 
    print(a, b, c) 
end 

alter_inside('a') --> 11  6  7    
alter_inside('b') --> 5 11  7    
alter_inside('c') --> 5  6 11 

你可以以不同的方式寫此,使用普通的功能,而不是用表讀/寫操作(__index__newindex)相結合。


§2.4 – Metatables and Metamethods如果上述使用元表的是你一個全新的課題。


在Lua中5.2+,你可以使用特殊_ENV表來調整當前塊的環境,但要注意,這是不一樣的使用local變量。

local function clone (t) 
    local o = {} 

    for k, v in pairs(t) do o[k] = v end 

    return o 
end 

local function alter_inside (key) 
    local _ENV = clone(_ENV) 

    a = 5 
    b = 6 
    c = 7 

    _ENV[key] = 11 

    print(a, b, c) 
end 

alter_inside('a') --> 11  6  7    
alter_inside('b') --> 5 11  7    
alter_inside('c') --> 5  6 11 

最後一點,也認爲這(AB)利用當地人的可能不是最好的辦法。

在適當的情況下,您可以簡單地將變量存儲在表中,以獲得相同的結果,而且開銷要小得多。強烈建議使用這種方法。

local function alter_inside (key) 
    -- `ls` is an arbitrary name, always use smart variable names. 
    local ls = { a = 5, b = 6, c = 7 } 

    ls[key] = 11 

    print(ls.a, ls.b, ls.c)  
end 

alter_inside('a') --> 11  6  7    
alter_inside('b') --> 5 11  7    
alter_inside('c') --> 5  6 11 

不要挖你一個洞,試圖解決不必要的問題。

+0

你的代碼不起作用。 '本地a = 1; print(a,_L ['a']) - > 1 nil' –

+0

看起來像Lua 5.1和5.2+之間的差異,大概是由於本地環境的不同。我在整個答案中鏈接了5.3文檔,但承認只在5.1中測試過這些代碼。我沒有精力讓這些代碼在各個版本之間移植,如果它甚至可能的話,考慮到它只是一個理論上可能的簡單例子。同樣,建議不要在生產中使用這種內省編程。該手冊警告不要使用除調試以外的其他任何調試庫,因爲它跟蝸牛一樣慢。 – Oka

+0

您可以請求解決方案上方的警告。這不僅僅是壞習慣 - 由於很多原因,這很可怕,因爲你可能認識你自己。 –