能否给lua加上类型_元表

一个类是什么?就是把一些共有的部分(成员:变量、函数)抽出来放到一起。

而每个成员都有一个名字,所以很容易想到能否给lua加上类型_递归_02


最简单的是这样子的:

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')

能否给lua加上类型_能否给lua加上类型_03


但是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)

能否给lua加上类型_键值对_04

添加新成员限制、访问不存在成员限制

使用不存在的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)

能否给lua加上类型_能否给lua加上类型_05