Lua 学习笔记(6)元表(metatable)与元方法(metamethod)

Lua 学习笔记(6)元表(metatable)与元方法(metamethod)

《Lua程序设计》


​ Lua中每个值都有一套预定义的操作集合。例如数字的相加,字符串的连接。当Lua要把两个表相加时,会检查元表是否有个叫__add的字段,有的话就调用(即 元方法)。

local mt = {}
MyTable = {}
function MyTable.new(l)
  local set = {}
  setmetatable(set, mt)
  for _, v in ipairs(l) do set[v] = true end
  return set
end

function MyTable.union(a,b)
	local res = {}
	for k in pairs(a) do res[k] = true end
	for k in pairs(b) do res[k] = true end
	return res
end

function MyTable.tostring(t)
	local l = {}
	for e in pairs(t) do
		l[#l + 1] = e
	end
	return "{" .. table.concat(l, ", ").. "}"
end

function MyTable.print(s)
	print(MyTable.tostring(s))
end

local t1 = MyTable.new{1,2,3}			-- 元表格式创建
local t2 = setmetatable({[1] = true,[4] = true},mt)		--匿名格式创建

mt.__add = MyTable.union			-- 相当于重载‘+’运算符

MyTable.print(t1)         --> {1, 2, 3}
MyTable.print(t2)         --> {4, 1}
MyTable.print(t1 + t2)    --> {1, 2, 3, 4}

local t3 = MyTable.new{1,2}
t3 = t3 + 8		--如果第一个值有元表且有__add,用第一个值的元方法,否则用第二个,如果两个都没元方法,报错。

算术类型

  • __add:加法
  • __mul:乘法
  • __sub:减法
  • __div:除法
  • __unm: 相反数
  • __mod:取模
  • __pow:乘幂
  • __concat:连接操作

关系类型

  • __eq:等于。两个对象拥有不同元方法时,等于操作会直接返回false
  • __lt:小于
  • __le:小于等于

NAN: Not a Number,未定义的值。

库定义的元方法

  • __tostring:转换成字符串
  • __metatable:如果设置了该字段,调用getmetatable就会返回这个字段的内容,调用setmetatable就会引发一个报错(cannot change protected metatable)。

__index元方法

  • table访问字段时,如果访问不到,会调用__index元方法。用于table的查询。
  • 使用rawget方法可以绕过元方法。
Window = {}
Window.prototype = {x = 0,y = 0, width = 100, height = 100}
Window.mt = {}
function Window.new(o)
  setmetatable(o, Window.mt)
  return o
end

Window.mt.__index = function(table, key)
  return Window.prototype[key]
end

w = Window.new{x = 10, y = 20}
print(w.x)      --> 10
print(w.width)  --> 100
print(w.z)      --> nil

__newindex

  • 用于table的更新,即对table不存在的值赋值时,就会调用__newindex元方法。

  • 使用rawset方法可以绕过元方法。

具有默认值的table

function setDefault(t, d)
    local mt = {__index = function() return d end}
    setmetatable(t, mt)
end
tab = {x = 10, y = 20}
print(tab.x, tab.z)		--> 10 nil
setDefault(tab, 0)
print(tab.x, tab.z)		--> 10 0

你可能感兴趣的:(Lua,Lua,学习笔记,lua)