表类
一个类是什么?就是把一些共有的部分(成员:变量、函数)抽出来放到一起。
而每个成员都有一个名字,所以很容易想到
最简单的是这样子的:
Person = {
name = '张伟',
sex = '男',
height = 175,
weight = 130,
age = 30,
Say = function(word)
print(name..':'..word)
end
}
Person.Say('Hi')
但是这样会报错,因为Say函数中是找不到name的。写过python的应该比较清楚,Say函数内需要一个self参数来找到实例,所以改为:
Person = {
name = '张伟',
sex = '男',
height = 175,
weight = 130,
age = 30,
Say = function(self, word)
print(self.name..':'..word)
end
}
Person.Say(Person, 'Hi')
但是Person.Say(Person, ‘Hi’)这句话感觉很麻烦,所以Lua提供了一种比较简单的写法:
Person:Say('Hi')
将点改为冒号可以省略第一个参数self。
当然方法可以在外面扩充,其实就是表添加新的键值对:
Person = {
name = '张伟',
sex = '男',
height = 175,
weight = 130,
age = 30,
}
function Person.Say(self, word)
print(self.name..':'..word)
end
-- function Person:Say(word)
-- print(self.name..':'..word)
-- end
Person:Say('Hi')
类的实现
表的[键-值]查找方式
如果你已经学习过了元表,那么下面的这个流程你应该是知道的
- 查找表table中的键key
- 有
- 返回value
- 没有
- 如果设置过metatable,且metatable存在__index键
- 递归metatable的__index,即
getmetatable(table).__index.key
- 否则返回nil
相信看完后你就知道怎么模拟类了。
最基础的版本
我们的实例是一个表(实例表),这个表的metatable设置为Person表(类表)。类表再设置__index键为自身,那么访问实例的成员时就相当于去这个类表中找了。
-- 类表
Person = {
new = function(self)
local obj = setmetatable({},self)
return obj
end,
name = '张伟',
sex = '男',
height = 175,
weight = 130,
age = 30,
Say = function(self, word)
print(self.name..':'..word)
end,
}
Person.__index = Person
-- 创建实例表
local a = Person:new()
a:Say('Hi')
最重要的是: table变量拥有独立的元表,可以看成,每次对表设置元表,都是从被设置为元表的那个表Copy一份。
-- 创建实例表
local a = Person:new()
local b = Person:new()
b.name = 'B'
a.name = 'A'
print(b.name)
print(a.name)
print(Person.name)
添加新成员限制、访问不存在成员限制
使用不存在的key时table会自动创建对应的键值对,但是这个和我们的类肯定是冲突的,所以加了__index限制(读取不存在键的值)和__newindex限制(修改不存在键的值)
-- 类表
Person = {
-- 成员
name = '张伟',
Say = function(self, word)
print(self.name..':'..word)
end,
-- 类的构造
new = function(self)
local obj = setmetatable({},self)
return obj
end,
__newindex = function(self, key, value)
if type(Person[key]) == 'nil' then
error("成员不存在:" .. key)
else
Person[key] = value
end
end,
__index = function(self, key)
-- 一定不能写成self.key,否则会无限递归找key
if type(Person[key]) == 'nil' then
error("成员不存在:" .. key)
else
return Person[key]
end
end,
}
-- 创建实例表
local a = Person:new()
print(a.name)
print(a.sex)