一.元表的概念
Lua模拟类和对象,理解主表/元表关系是关键,有表A和表B,A是主表,B是元表(子表),那么我们可以通过主表访问元表中的元素。实现代码如下:
--[[
tableA = {} --表A [主表]
tableB = {} --表B [元表/子表]
setmetatable(tableA, tableB) -- tableB就是tableA的元表.
print(getmetatable(tableA)) -- 判断tableA是否有元表
--]]
tableA = {name = "lsw", age = 100}
tableB = {gender = "男", address = "湖北武汉"}
setmetatable(tableA, tableB)
tableB.__index = tableB -- 设置元表的__index索引.
print(tableA.name, tableA.age)
--print(tableA["name"])
print(tableA.gender, tableA.address)
- 表 A 内有自己键值对元素,表 B 内也有自己的键值对元素,同时表 B 还是 表 A 的元表,两个表建立了“从属关系”,一般我们都是直接访问表 A。
- 我们可以直接通过“表名.键名”的方式访问表 A 中的成员,但是元表内的 成员,我们是访问不到的,会返回 nil。
- 如何通过“表名.键名”直接访问到元表中的成员哪??? 我们需要设置元表的“__index 索引”,让这个索引指向元表自身,代码如下: 元表名.__index = 元表名
- 设置完毕__index 索引后,我们再使用“表名.键名”的方式访问成员,如 果表 A 中没有,就会自动访问表 B 中的成员。
二.Lua模拟类
--初始化了一个类.
Person = {name, age, gender, address = "中国"} --在Person类中模拟字段.
--模拟构造方法.
function Person:New()
obj = {} --初始化一个新的表.
setmetatable(obj, Person) --把当前的类[表]设置为新表的元表.
Person.__index = Person --指定元表的__index索引.
return obj
end
--模拟一个方法.
function Person:Show()
print(self.name, self.age, self.gender, self.address)
end
--实例化对象.
lkk = Person:New()
lkk.name = "lsw"
lkk.age = 110
lkk.gender = "男"
lkk.address = "湖北武汉"
lkk:Show()
mk = Person:New()
mk.name = "Monkey"
mk.age = 10
mk.gender = "男"
mk:Show()
print(lkk == mk)
三.进一步完善
--创建一个Hero类.
Hero = {name, hp, mp, attack} --定义相关字段.
--定义构造方法.
function Hero:New(name, hp, mp, attack)
local obj = {}
--setmetatable(obj, Hero)
--Hero.__index = Hero
setmetatable(obj, self)
self.__index = self
self.name = name
self.hp = hp
self.mp = mp
self.attack = attack
return obj
end
--定义相关方法.
function Hero:Attack1()
print(self.name .. "攻击方法一执行啦..")
end
function Hero:Attack2()
print(self.name .. "攻击方法二执行啦..")
end
function Hero:ToString()
print(string.format("角色名:%s,生命值:%s,法力值:%s,攻击力:%s", self.name, self.hp, self.mp, self.attack))
end
--实例化对象.
--mk = Hero:New()
--mk.name = "mkcode"
--mk.hp = 1000
--mk.mp = 500
--mk.attack = 100
mk = Hero:New("Monkey", 9999, 8888, 7777)
mk.hp = 1000000
mk:Attack1()
mk:Attack2()
mk:ToString()
--在 Lua 语言的构造方法中,我们可以做两件事情:
--①必须要完成一个新的“对象的实例化”,也就是初始化一个新的表;
--②同时还可以完成对象字段的初始化,这一步是可选操作。
- 在构造方法中指定__index 索引的时候可以用 self 代表当前“类”;
- 在构造方法中使用 self 表示当前类中的成员。
四.继承关系模拟
--创建一个动物类.
Animal = {name} --字段.
--构造方法.
function Animal:New(name)
local obj = {}
setmetatable(obj, self)
self.__index = self
self.name = name
return obj
end
--普通方法.
function Animal:ToString()
print(self.name .. "Animal类中的方法")
end
--子类继承父类.
Cat = Animal:New(nil)
--子类的构造方法.
function Cat:New(name)
local obj = Animal:New(name)
setmetatable(obj, self)
self.__index = self
--self.name = name
return obj
end
--子类当的普通方法.
function Cat:Eat(food)
print(self.name .. "吃:" .. food)
end
--[[
--创建对象.
jfm = Animal:New("加菲猫")
jfm:ToString()
print(jfm.name)
--]]
--通过子类实例化对象.
jfm = Cat:New("加菲猫")
jfm:ToString()
jfm:Eat("鱼")
print(jfm.name)
tom = Cat:New("汤姆")
tom:ToString()
tom:Eat("杰瑞")
print(tom.name)