Lua面向对象

Lua面向对象

在Lua语言中可以使用函数setmetatable来设置或修改任意表的元表

我们只能为表设置元表;如果要为其他类型的值设置元表,则必须通过C代码或者调试库完成(该限制存在的主要原因是为了防止过度使用对某类型的所有值生效的元表。Lua语言老版本中的经验表明,这样的全局设置经常导致不可重用的代码)。字符串标准库为所有的字符串都设置了同一个元表,而其他类型在默认情况中都没有元表。

Lua语言会按照如下步骤来查找元方法:如果第一个值有元表且元表中存在所需要的元方法,那么Lua语言就是用这个元方法,与第二个值无关;如果第二个值有元表且元表中存在所需的方法,Lua语言就是用这个元方法;否则,Lu语言就抛出异常。

元表

在 Lua table 中我们可以访问对应的 key 来得到 value 值,但是却无法对两个 table 进行操作(比如相加)。

因此 Lua 提供了元表(Metatable),允许我们改变 table 的行为,每个行为关联了对应的元方法。

例如,使用元表我们可以定义 Lua 如何计算两个 table 的相加操作 a+b。

当 Lua 试图对两个表进行相加时,先检查两者之一是否有元表,之后检查是否有一个叫 __add 的字段,若找到,则调用对应的值。 __add 等即时字段,其对应的值(往往是一个函数或是 table)就是”元方法”。

  • setmetatable(table,metatable): 对指定 table 设置元表(metatable),如果元表(metatable)中存在 __metatable 键值,setmetatable 会失败。
  • getmetatable(table): 返回对象的元表(metatable)。
1
2
3
mytable = {}                          -- 普通表 
mymetatable = {} -- 元表
setmetatable(mytable,mymetatable) -- 把 mymetatable 设为 mytable 的元表

元方法

key
__index 元方法 当你通过键来访问 table 的时候,如果这个键没有值,那么Lua就会寻找该table的metatable(假定有metatable)中的index 键。如果index包含一个表格,Lua会在表格中查找相应的键。(可以实现lua面向对象)
__newindex 元方法 newindex 元方法用来对表更新,当你给表的一个缺少的索引赋值,解释器就会查找newindex 元方法:如果存在则调用这个函数而不进行赋值操作。
__call 元方法 __call 元方法在 Lua 调用一个值时调用
__tostring 元方法 _tostring 元方法用于修改表的输出行为

这里主要介绍__index 元方法:

Lua语言中的一张表就是一个对象,表与对象一样,拥有一个与其值无关的标识(self),在进行函数调用时,使用:会隐式传递self

1
2
3
4
5
6
local t = {}
function t:talk()
print("hello")
end
t.talk(self)
t:talk()

1
local t = {} --类

封装

1
2
3
4
5
local t = {}
t.name = "zhangsan"
t.sayHello = function ()
print("hello world")
end

继承

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
local Base = {}
function Base:new(o)
o = o or {}
self.__index = self
o.super = self
setmetatable(o,self);
return o
end

Base.name = "animal"
Base.age = 1
Base.sayHello = function()
print("I am animal")
end

local dog = Base:new()
-- 重写父类方法
function dog:sayHello()
print("i am dog")
end

dog.super:sayHello()
dog:sayHello()

多继承

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
--当 __ index是一个函数是,Lua会以表和没找到的字段为参数调用这个函数,如果是一个表,则会直接访问这个表。
--在表'plist'的列表中查找'k' t是c,k是查找的字段
local function search(k,plist)
for i=1,#plist do
local v = plist[i][k] -- 尝试第‘i’个超类
if v then return v end
end
end

function createClass(...)
local c= {} --新类
local parents = {...} --父类列表
--在父类列表中查找类的缺少的方法
setmetatable(c,{__index = function(t,k)
return search(k,parents)
end})
-- 将‘c’作为其实例的元表
c.__index = c
--为新类定义一个新的构造函数
function c:new(o)
o = o or {}
setmetatable(o,c)
return o
end
return c -- 返回新类
end

local talk = {} --说话类
function talk:new(o)
o = o or{}
self.__index = self
setmetatable(o,self)
return o
end

function talk:say(msg) --说话类方法
print(msg)
end

local Perforamnce = {} --表现类
function Perforamnce:new(o)
o = o or{}
self.__index = self
setmetatable(o,self)
return o
end

function Perforamnce:init(performanceTye) --表现类的初始化
print(performanceTye)
end

local dog = createClass(Perforamnce,talk) --dog继承talk和Performance类
dog:init("dog")
doy:say("wangwangwang")

Lua的metatable和Lua的面向对象实现 | zhutaorun’s Blog

Lua 面向对象 | 菜鸟教程

Lua 元表(Metatable) | 菜鸟教程