您的位置:首页 > 编程语言 > Lua

lua中的面向对象

2020-08-17 18:47 1401 查看

lua实现面向对象编程是基于元表

metatable
,元方法
__index
来实现的。

lua中的语法糖

lua的table中可以定义函数,如下图:

local a = {
x = 1,
print = function(obj)
print("x=" .. obj.x)
end
}

如上图,定义了一个名叫

a
的table,可以通过调用
a.print(a)
来打印table
a
中的
x
key对应的value值。

像是

a.print(a)
这种形式,在lua中可以简化为
a:print()
,这是lua中的语法糖,使用
:
而不是
.
,lua会默认把 “调用者” 给传递进去。

元表 metatable

元表的表现行为类似于操作符重载,比如我们可以重载 __add,来计算两个 Lua 数组的并集;或者重载 __tostring,来定义转换为字符串的函数。

Lua 提供了两个处理元表的函数:

  • setmetatable(table, metatable), 用于为一个 table 设置元表
  • getmetatable(table),用于获取 table 的元表

比如:

local version = { major = 1, minor = 1, patch = 1 }
version = setmetatable(version,
{
__tostring = function(t)
return string.format("%d.%d.%d", t.major, t.minor, t.patch)
end
})
print(tostring(version))        -- 1.1.1

这段代码的作用就是重载了

version
表的
tostring()
方法,如果不重载的话,直接调用默认方法,那么打印结果是:

local version = { major = 1, minor = 1, patch = 1 }
print(tostring(version))        -- table: 0x000647a8

元方法: __index

我们在 table 中查找一个元素时,首先会直接从 table 中查询,如果没有找到,就继续到元表的 __index 中查询。

local version = { major = 1, minor = 1}
version = setmetatable(version,
{
__index = function(t, key)
if key == "patch" then
return 2
end
end,
__tostring = function(t)
return string.format("%d.%d.%d", t.major, t.minor, t.patch)
end
})
print(tostring(version))        -- 1.1.2

这样当

t.patch
取不到值时,就会去
__index
中进行查找。

__index 不仅可以是一个函数,也可以是一个table。

local version = { major = 1, minor = 1}
version = setmetatable(version,
{
__index = { patch=3 },
__tostring = function(t)
return string.format("%d.%d.%d", t.major, t.minor, t.patch)
end
}
)
print(tostring(version))        -- 1.1.3

上面的代码可以变换为如下形式:

local version = { major = 1, minor = 1}
local mt = {
__index = {
patch=3
},
__tostring = function(t)
return string.format("%d.%d.%d", t.major, t.minor, t.patch)
end
}
version = setmetatable(version, mt)
print(tostring(version))        -- 1.1.3

元方法:__call

使用

__call
可以让 table 被调用。

local version = { major = 1, minor = 1, patch = 1 }
local function print_version(t)
print(string.format("%d.%d.%d", t.major, t.minor, t.patch))
end
version = setmetatable(version,
{
__call = print_version
}
)

version()       -- 1.1.1

面向对象

lua-resty-mysql 是OpenResty 官方的 MySQL 客户端,里面就使用元表模拟了类和类方法,它的使用方式如下所示:

local mysql = require "resty.mysql"     -- 先引用 lua-resty 库
local db, err = mysql:new()     -- 新建一个类的实例
db:set_timeout(1000)    -- 调用类的方法

那么lua-resty-mysql的源码是如何实现的呢?

local _M = { _VERSION = '0.21' } -- 使用 table 模拟类
local mt = { __index = _M } -- mt 即 metatable 的缩写,__index 指向类自身

-- 类的构造函数
function _M.new(self)
local sock, err = tcp()
if not sock then
return nil, err
end
return setmetatable({ sock = sock }, mt) -- 使用 table 和 metatable 模拟类的实例
end

-- 类的成员函数
function _M.set_timeout(self, timeout)
-- 使用 self 参数,获取要操作的类的实例
local sock = self.sock
if not sock then
return nil, "not initialized"
end
return sock:settimeout(timeout)
end

上面的代码中,

-M
这个table代表的就是mysql类,
_M.new(self)
方法中返回一个
setmetatable({ sock = sock }, mt)
就是返回一个类的对象,
socket
这个属性就是这个对象的成员属性,而不是类的属性。

内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: