Lua中rawset 函式使用
當我們只想單純的呼叫table裡的欄位或者給table欄位賦值時,我們可以通過rawget函式來忽略元表的__index作用,只從table中
查詢例如:
local father = { --house=1, sayHello = function() print("大家好,我是father."); end } local temp ={ __index = father, __newindex = function(table, key) print(key .. "欄位是不存在的,不允許給它賦值!"); end } son = { car=1 } setmetatable(son, temp) --把son的metatable設定為father print(rawget(son, "house")); print(rawget(son, "car")); rawset(son, "house", "10"); rawset(son, "sayHello", function() print('============') end); print(son.house); son.sayHello()
上面程式碼輸出:
nil
1
10
============
rawget函式的第一個引數是要呼叫的table,第二個引數是table的欄位名。
因此,通過rawget呼叫son的house欄位,返回nil,而呼叫car欄位,則能正確取得值。
同樣的是,rawset函式可以忽略元表的__newindex功效,單純地給house賦值
另外在網上看到有個人用__index和__newIndex實現了一個只讀的函式,挺有意思的這裡貼一下
local function readOnly(t) local newT = {}; local mt = { __index = t, __newindex = function() error("別修改我!我是隻讀的!"); end } setmetatable(newT, mt); return newT; end local days = readOnly({"星期一", "星期二", "星期日"}); days[2] = "星期三哪去了啊?" ;
輸出:[LUA-print] LUA ERROR: [string "src/main.lua"]:130: [string "src/main.lua"]:76: 別修改我!我是隻讀的!
沒錯,通過readOnly產生的table,是無法進行賦值操作的。
那麼,原理呢?我們來一步步思考吧:
a.首先,readOnly會建立一個新的table,然後把我們傳進去的table作為__index元方法。
b.元表裡還增加了__newindex,用來阻止不存在欄位的賦值操作。
c.readOnly返回的table已經不是我們原來的table了,它是一個空的table,但是它被設定了一個新的元表。
d.開始對days執行賦值操作:days[2] = “星期三哪去了啊?” 。
e.days是一個空的table,所以它不存在這個欄位,也因此,會呼叫__newindex元方法,賦值失敗。
f.如果只是呼叫days,不進行賦值,如:print(days[2]); 則能正常輸出欄位值,因為days的元表裡有__index元方法。雖然days中不存在2這個欄位,但是可以通過__index找到這個欄位。
總而言之,最終,days成為了一個只可以讀取,不能進行賦值操作的table。
節選自:https://www.jb51.net/article/55160.htm