Lua: Metatables
Lua |
---|
Basics |
Intermediate |
Advanced |
|
XLua |
Add to this template |
Metatables are a form of table that may be attached to any other table, including itself.
An individual table may only have one metatable attached, but that metatable may have its own metatable, and this may be cascaded indefinitely. An individual metatable may be attached to any number of tables, however.
The primary purpose of metatables is to allow operations on tables (and other objects) that normally would not be allowed; for example, addition, an operation that is by default impossible:
table1 = {1, 2, 3}
table2 = {10, 20, 30}
table3 = table1 + table2 -- Returns an error
Because tables may contain any number of separate non-nil types of data, adding tables is by default impossible, and will always return an error; there are many ways to define what "add" means for a set of data, so Lua leaves this distinction to the developer.
To allow tables to be added together, the metamethod __add must be defined within a metatable, and that metatable must then be referenced by a regular table:
Metatables are set using the setmetatable() function, which takes the main table as its first argument and the metatable as the second. getmetatable() can be used to retrieve the metatable assigned to the table given as the first argument, unless the __metatable field is defined in which case that value is returned instead.
Example code
function newTable(t_data)
return setmetatable(t_data, mt) -- Assigns the same metatable to the table passed to this function
end
metatable = {
__add = function (a, b)
local sum = { } -- This is the new table we will be returning.
for i = 1, math.max(#a, #b) do -- Runs as long as entries exist in the larger table
sum[i] = (a[i] or 0) + (b[i] or 0) -- Adds one table entry to its correspondent, using 0 for entries that don't exist
end
return newTable(sum) -- Set the metatable or we can't use this table for future addition operations!
end,
__tostring = function (t)
return table.concat(t, " ") -- Control how this table is coerced into a string
end,
}
table1 = newTable {1, 2, 3}
table2 = newTable {10, 20, 30}
table3 = table1 + table2 -- valid after much headache
print(table3) -- Was it worth it?