Objective
This blog post will be illustrated with a few simple examples, consolidate understanding of __index and __newindex and deepen understanding of LUA's meta tables and meta methods, and if you are not familiar with Lua's Wenzu and Meta methods, refer to this article: Wenzu and Meta methods in Lua.
Table with default values
As we all know, the default value for any field in the table is nil, but with the meta table, we can easily modify this rule as follows:
Copy Code code as follows:
function SetDefault (TB, defaultvalue)
Local MT = {__index = function () return DefaultValue end}
Setmetatable (TB, MT)
End
Local TB1 = {x = ten, y = 20}
Print (tb1.x, tb1.z)--> Nil
SetDefault (TB1)--> set the default value
Print (tb1.x, tb1.z)--> 10 100 This is the default value.
As you can see, in the code, the SetDefault function creates a new meta table for all tables that require a default value. If you're going to create a lot of things that need to default to table, the cost of this approach may be quite large. Because the default value defaultvalue in the meta table is associated with the Meta method, SetDefault cannot use the same meta table for all tables. If you want to use the same meta table for a different default worth table, you need to store the default values for each of the meta tables in the table itself, and you can use an extra field to store the default values. For example, the following code:
Copy Code code as follows:
Local MT = {__index = function (t) return t.___ end}
function SetDefault (TB, defaultvalue)
tb.___ = defaultvalue-thank Hellowei for the Sharp review. See comments for details
Setmetatable (TB, MT)
End
The "___" in the code above is a name to prevent the name from conflicting; If so, you are also worried about the name of the conflict, to ensure the uniqueness of the key in the table, only to create a new table and use it as a key, each newly created table is a unique address, For example, the following code:
Copy Code code as follows:
Local key = {}-the only key
Local MT = {__index = function (TB) return Tb[key] End}
function SetDefault (TB, defaultvalue)
Tb[key] = DefaultValue
Setmetatable (TB, MT)
End
Log access to table
Sometimes, a specific requirement, we need to record all access to a table, whether it is query or update, we need to log. How is this done? As we all know, the __index and __newindex in the meta table work when there is no index in the table that needs to be accessed, so only a table is kept empty and then the __index and __newindex meta methods are set. It is possible to record all access to it.
To monitor all access to a table, you should create a proxy for the real table. The proxy is an empty table where the __index and __newindex meta methods can be used to track all access and redefine access to the original table. This is the idea, and then look at the code:
Copy Code code as follows:
Local t = {}--the original table
--Keep a reference to the original table
Local _t = t
--Create a proxy
t = {}
--Create a meta table
Local MT = {
__index = function (T, K)
Print (access to element ...). ToString (k))
return _t[k]
End
__newindex = function (t, K, V)
Print ("Update of Element" ...) ToString (k))
_t[k] = V
End
}
Setmetatable (T, MT)
T.x =--Update of element x
Print (T.x)--Access to element x
If you want to monitor several tables at the same time, you do not need to create a different meta table for each table; instead, whenever you associate each agent with its original table in some form, and all agents share a common meta table. This problem is similar to the problem associated with setting the table default value, and it also saves the original table in a special field in the proxy table. The code is as follows:
Copy Code code as follows:
--Create a unique index
Local index = {}
--Create a meta table
Local MT = {
__index = function (T, K)
Print (access to element ...). ToString (k))
return T[index][k]
End
__newindex = function (t, K, V)
Print ("Update of Element" ...) ToString (k))
T[index][k] = V
End
}
function Track (t)
Local proxy = {}
Proxy[index] = t
Setmetatable (proxy, MT)
Return proxy
End
Local T = {}
Local proxy = track (t)
proxy.x = 10
Print (proxy.x)
Read-only table
With the concept of an agent, you can easily implement a read-only table. Just need to keep track of all the updates to the table and raise an error. For the query, we do not have to go to the museum, just want to manage the update operation of the table, nonsense do not say, to paragraph simple code, natural at a glance.
Copy Code code as follows:
function ReadOnly (t)
Local proxy = {}
--Create a meta table
Local MT = {
__index = T,
__newindex = function (t, K, V)
Error ("Attempt to update a read-only table", 2)
End
}
Setmetatable (proxy, MT)
Return proxy
End
Local Tbdemo = Readonly{1, 2, 3, 4, 5}
Print (tbdemo[1])
TBDEMO[1] = 20
The __index corresponds to the original table in the Meta table, and when the original table is updated, an error message is displayed: Attempt to update a read-only table.
Summarize
This article gives a detailed explanation and analysis of the use of __index and __newindex in Lua, and provides practical code to deepen the understanding of the meta tables and meta methods in Lua, where meta tables and meta methods are too often in Lua, Many advanced programming skills and special requirements are based on the meta table and meta method to achieve, so, also hope that we can read this article, but also hope that my article for everyone to help.