1.元表
通过设置元表可以让我们对两个table进行特定操作,如(_add 可以定义两个table的相加操作)。
- setmetatable(table,metatable): 对指定 table 设置元表(metatable),如果元表(metatable)中存在 __metatable 键值,setmetatable 会失败。
- getmetatable(table): 返回对象的元表(metatable)。
- _index元方法: 当你通过键来访问 table 的时候,如果这个键没有值,那么Lua就会寻找该table的metatable(假定有metatable)中的__index 键。如果__index包含一个表格,Lua会在表格中查找相应的键。
- _newindex元方法: 当你给表的一个缺少的索引赋值,解释器就会查找__newindex 元方法:如果存在则调用这个函数而不进行赋值操作。
[参考](Lua 元表(Metatable) | 菜鸟教程)
-- 设置元表
mytable = {} -- 普通表
mymetatable = {} -- 元表
setmetatable(mytable,mymetatable) -- 把 mymetatable 设为 mytable 的元表
-- __index元方法测试
mytable = setmetatable({key1 = "value1"}, { __index = { key2 = "metatablevalue" } })
print(mytable.key1,mytable.key2) -- value1 metatablevalue
-- __newindex元方法测试
mymetatable = {}
mytable = setmetatable({key1 = "value1"}, { __newindex = mymetatable })
print(mytable.key1) -- value1
mytable.newkey = "新值2"
print(mytable.newkey,mymetatable.newkey) -- nil 新值2
mytable.key1 = "新值1"
print(mytable.key1,mymetatable.key1) -- 新值1 nil
2.lua面向对象
面向对象三大特性:继承、封装、多态
[参考](Lua 面向对象(实现类的创建和实例化、封装、继承、多态) - Fflyqaq - 博客园)
2.1 lua类创建与实例化
person.lua
-- 字段
person = {name = 'kk',age = 18}
-- 方法
function person:run()
print('kk 移动')
end
-- 实例化
function person:new()
local self = {}
-- 使用元表,将_index赋值为person类
setmetatable(self,{__index = person})
return self
end
test.lua
require 'person'
-- 实例化person类
p1 = person:new()
-- 输出
p1.run()
2.2 lua封装
-- 实现对字段进行封装,使其只能通过方法进行访问
function person(name,age)
-- 初始化
local self = {
_name = name,
_age = age
}
-- 封装方法
local getName = function()
return self._name
end
local getAge = function()
return self._age
end
local setAge = function(age)
self._age = age
end
local printInfo = function()
print('name='..self._name..' age='..self._age)
end
-- 只返回方法
return{
getName = getName,
getAge = getAge,
setAge = setAge,
printInfo = printInfo
}
end
p1 = person('kk',10)
print(p1._age) -- nil
print(p1.getAge()) -- 10
p1.setAge(20)
print(p1:getAge()) -- 20
p1:printInfo() -- name=kk age=20
2.3 lua继承
-- 基类 person 子类 boy
person = { name ='kk',age = 10}
function person:new(t)
-- t 为空时,返回一个新表
t = t or {}
setmetatable(t,self)
self.__index = self
return t
end
function person:say()
print('my name is '..self.name)
end
-- 相当于继承
boy = person:new()
-- boy中找不到会去person中找
boy:say() -- my name is kk
-- 重新赋值
boy.name = 'kangkang'
boy:say() -- my name is kangkang
-- 修改boy中的值不会影响person
person:say() -- my name is kk
2.4 lua多态
person = {
name = 'kk',
age = 10
}
-- 重载:lua会自动适应传入参数的个数
function person:getInfo(name,age)
if name == nil then
name = self.name
end
if age == nil then
age = self.age
end
print('name:',name,age)
end
function person:new(o)
o = o or {}
setmetatable(o,self)
self.__index = self
return o
end
person:getInfo() -- name: kk 10
person:getInfo('KK',100) -- name: KK 100
boy = person:new()
--调用基类方法
boy:getInfo('boy',100) -- name: boy 100
-- 重写
function boy:getInfo(name,age)
if name == nil then
name = self.name
end
if age == nil then
age = self.age
end
print('my name is '..name..' age is '..age)
end
boy:getInfo() -- my name is kk age is 10
2.5 class.lua 实现类
-- 表_class的key为类,value作为类的虚表,存储类的字段、方法
local _class = {}
-- 为什么要用虚表
--[[
使用虚表的话,类本身的元素是稳定的,
所有的变化都在虚表中进行,这样封装了变化、以便于继承的实现
]]--
function class(super)
-- 要创建的类class_type
local class_type = {}
-- 构造函数 ctor-是否存在构造函数 super-记录父类,基类是nil
class_type.ctor = false
class_type.super = super
-- class_type类型的虚表,虚表中包含class_type中的元素
local vtb1 = {}
_class[class_type] = vtb1
-- 设置元表
-- 给表添加新元素时,会在虚表中也添加
setmetatable(class_type,{
-- __newindex:用于对表更新,当对当前表缺少的索引赋值时,解释器会查找__newindex元方法,如果存在则会调用这个函数
__newindex = function(t,k,v)
vtb1[k] = v
end,
-- __index:用于查找,当查找当前表不存在的索引时,解释器会查找__index元方法,如果存在则会调用这个函数
__index = function(t,k)
return vtb1[k]
end
})
-- super不为空,表示为继承
if super then
setmetatable(vtb1,{
__index = function(t,k)
--从基类中查找要找的元素,找到就放入到派生类虚表中
local ret = _class[super][k]
vtb1[k] = ret
return ret
end
})
end
-- 给类型class_type创建实例对象
-- 1 先依次从最顶层基类中调用构造方法
-- 2 设置元表
class_type.new = function(...)
--生成类对象
local o = {}
do
-- 递归调用构造函数
local create
create = function(c,...)
-- super不为空说明有基类
if c.super then
create(c.super,...)
end
-- 调用构造函数
if c.ctor then
c.ctor(o,...)
end
end
create(class_type,...)
end
-- 设置o的__index为class_type的虚表(给新对象赋值类的属性)
setmetatable(o,{ __index = _class[class_type] })
return o
end
return class_type
end
-- 创建基类
person = class()
person.name = 'zz'
person.age = 10
print(person.name) -- zz
-- 设置person类的构造函数
function person:ctor()
print('person ctor')
end
function person:run()
print('person run')
end
-- 创建派生类boy,基类为person
boy = class(person)
boy:run() -- person run
function boy:ctor()
print('boy ctor')
end
function boy:run()
print('boy run')
end
-- 创建对象
local boy1 = boy.new() -- person ctor -- boy ctor
boy1:run() -- boy run
2.6 单例模式
apple.lua
require "class"
apple = class()
apple.color = 'empty'
-- 单例
apple.Instance = function ()
if nil == apple.m_instance then
apple.m_instance = apple.new()
end
return apple.m_instance
end
function apple:ctor()
print('apple ctor')
end
local a1 = apple.Instance()
a1.color = 'red'
local a2 = apple.Instance()
a2.color = 'green'
print('a1 color is '..a1.color) -- a1 color is green
print('a2 color is '..a2.color) -- a2 color is green