Lua中self 、自索引及其面向对象应用代码示例

简介: Lua中self 、自索引及其面向对象应用代码示例

一、Lua表的self标识

在lua中,表拥有一个标识:self。self类似于c++中的this指针和python中的self。在lua中,提供了冒号操作符来隐藏这个参数,例如:

t1 = {
    id = 1, 
    name = "panda",
    addr = "beijing"
}
-- 使用冒号语法实现
function t1:getId()
    return self.id
end
function t1:setId(val)
    self.id = val
end
t1:setId(10)
print(t1:getId())
-- 使用点语法实现
function t1.getName(obj)  -- 需要将表作为参数传入
    return obj.name
end
function t1.setName(obj, val)
    obj.name = val
end
t1.setName(t1, "mark")
print(t1.getName(t1))

运行结果:

冒号只是一种语法机制,提供的是便利性,并没有引入任何新的东西。使用冒号完成的事情,都可以使用点语法来完成。

两者有什么区别呢?

  1. lua 为冒号提供了独有的指令:self
  2. 从用法上来说,使用点语法实现需要传入表对象,而冒号就显得较为简洁了。

二、自索引

t2 = {id = 2, name = "lwang", age = 18}
meta_t2 = {
    -- __index = meta_t2,  -- 为什么写在这里不行,因为此时 meta_t2 还不存在,所以是nil
    addr = "shenzhen"
}
meta_t2.__index = meta_t2;  -- 自索引,自己索引自己
setmetatable(t2, meta_t2)
print(t2.addr)

运行结果:

三、自索引实现继承

father = {a = 1, b = 2}
function father:fatherSayHello()
    print("father say hello: ", father.a, father.b)
end
father.fatherSayHello()
father.__index = father
son = {a = 10, b = 20}
function son:sonSayHello()
    print("son say hello")
end
son.sonSayHello()
setmetatable(son, father)  -- 设置元表
son.sonSayHello()
son.fatherSayHello()  --子类son有元表,并且有__index = father,指向父类的表,调用父类的方法

运行结果:

四、Lua 模拟类的实例化(带参构造)

-- 4.  面向对象 类的实例化(带参构造)
stuInfo = {
    id = 1, 
    name = "panda",
    age = 18
}
-- stuInfo stu1 stu2 都是同一张表
stu1 = stuInfo
stu2 = stu1
print(stuInfo, stu1, stu2)
print(stuInfo.id, stu1.id, stu2.id)
stuInfo.id = 100
print(stuInfo.id, stu1.id, stu2.id) -- 都会休改为:100
print("")
stuInfo.__index = stuInfo  -- 设置自索引
function stuInfo:newInstance(tab)
    obj = tab or {}
    setmetatable(obj, self) -- 为obj设置元表为self 也就是stuInfo  谁调用newInstance,self就是谁
    -- self.__index = self
    return obj
end
-- stu3 接收newInstance出来的实例
stu3 = stuInfo:newInstance({id = 3, age = 20})
print("stu3: ", stu3.id, stu3.name, stu3.age)  -- name会使用stu3 元表也就是stuInfo中的name的值
print("")
stu4 = stu3:newInstance()
print("stu4: ", stu4.id, stu4.name, stu4.age)  -- 输出 nil nil nil 
print("")
stu3.__index = stu3   -- 设置自索引
stu5 = stu3:newInstance({id = 1111})
print("stu5: ", stu5.id, stu5.name, stu5.age)  -- 输出 nil nil nil 
print("")

运行结果:

结果分析:

为什么stu3可以正常输出,stu4为什么输出都是nil?

因为:stu3 = stuInfo:newInstance({id = 3, age = 20}) ,stu3 在实例化的过程中,传了参数:id 和 age 所以,id 和 age 直接输出3 和 20 没有问题,在stu3输出name的时候,因为stu3 没有name索引,会找自己的元表,也就是stuInfo,触发 stuInfo的__index因为stuInfo.__index 指向的是自己 (设置了自索引 stuInfo.__index = stuInfo),所以会到stuInfo表中找name 找到 name = “panda” 输出:panda

而,stu4是通过stu3实例化出来的(stu4 = stu3.newInstance())且没有传递参数,在输出stu4的id name 和 age 时,本身都没有,就会找stu4的元表,stu4的元表是stu3。 关键就在于 stu3 没有__index元方法,所以stu4输出的都是nil

如何让stu4 正常输出呢?两种解決方法:

-- 1. 为stu3 设置自索引
    stu3.__index = stu3  
    -- 2. 直接在newInstance 方法中 通过 self.__index = self 为调用者设置自索引
    function stuInfo:newInstance(tab)
        obj = tab or {}
        setmetatable(obj, self) -- 为obj设置元表为self 也就是stuInfo  谁调用newInstance,self就是谁
        self.__index = self  -- 为调用者设置自索引
        return obj
    end

五、多重继承

grandfather = {id = 1, name = "grandfather"}
grandfather.__index = grandfather
father = {name = "father"}
father.__index = father
-- 设置father的元表为grandfather
setmetatable(father, grandfather)
son = {name = "son"}
-- 设置son的元表为father
setmetatable(son, father)
print(grandfather.id, father.id, son.id) -- 输出: 1 1 1
print(grandfather.name, father.name, son.name) -- 输出: grandfather     father  son

运行结果:

结果分析:

先分析id:

  • grandfather.id 因为grandfather有id 所以直接输出1
  • father.id 因为father没有id索引,会找fahter的元表,也就是grandfather,触发grandfather的__index 此时__index指向grandfather本身,grandfather本身就是一张表,就会找自己有没有id索引,找到id = 1返回
  • son.id 因为son没有id索引,会找son的元表,也就是father,触发father的__index 此时__index指向father本身, father本身就是一张表,就会找自己有没有id索引,找到id = 1返回, 没有继续找会找fahter的元表,也就是grandfather,触发grandfather的__index 此时__index指向grandfather本身,grandfather本身就是一张表,就会找自己有没有id索引,找到id = 1返回

分析name:

name 索引因为都有,所以正常输出

六、子类重写父类方法

stuInfo = {
    id = 1, 
    name = "panda",
    age = 18,
    say = function()
        print("stuInfo say.")
    end
}
function stuInfo:newInstance(tab)
    obj = tab or {}
    setmetatable(obj, self) -- 为obj设置元表为self 也就是stuInfo  谁调用newInstance,self就是谁
    self.__index = self  -- 设置自索引
    return obj
end
function stuInfo:getId()
    return self.id
end
function stuInfo:setId(newId)
    self.id = newId
end
stu1 = stuInfo:newInstance()
stu2 = stu1:newInstance()
print(stuInfo, stu1, stu2)
print(stuInfo.id, stu1.id, stu2.id)  -- 如果子类没有赋值,默认会使用父类的值;如果父类的成员或方法发生变化会影响子类,前提是子类没有重写
stuInfo.age = 25
print(stuInfo.age, stu1.age, stu2.age)
stu1.id = 100   -- stu1以下都会改变  这就是重写
print(stuInfo.id, stu1.id, stu2.id)
print("")
stuInfo.say()
stu1.say()
stu2.say()
print("")
function stu1:say()    -- stu1 重写say方法
    print("stu1 say.")
end
stuInfo.say()
stu1.say()    -- stu1 调用自己的say方法
stu2.say()    -- stu2 调用stu1的say方法

运行结果

七、成员私有化

function personInfo()
    -- 将成员属性隐藏起来
    local members = {
        id = 1,
        name = "lwang",
        age = 25
    }
    local function getId()
        return members.id
    end
    local function getName()
        return members.name
    end
    local function setId(id)
        members.id = id
    end
    local function setName(name)
        members.name = name
    end
    -- 对外暴露的方法
    return {
        getId = getId,
        setId = setId,
        getName = getName,
        setName = setName
    }
end
p1 = personInfo()
print(p1.getId(), p1.getName())
p1.setId(22)
p1.setName("mark")
print(p1.getId(), p1.getName())

运行结果

相关文章
|
2月前
lua面向对象(类)和lua协同线程与协同函数、Lua文件I/O
Lua的面向对象编程、协同线程与协同函数的概念和使用,以及Lua文件I/O操作的基本方法。
32 4
lua面向对象(类)和lua协同线程与协同函数、Lua文件I/O
|
6月前
|
监控 数据处理 开发者
利用Lua代码简化局域网管理软件开发
使用Lua脚本语言可以提升局域网管理软件的开发效率和代码可维护性。示例包括:使用LuaSocket扫描局域网设备;通过动态加载和应用配置文件展示配置管理;利用实时监控功能,当网络流量超过阈值时触发警报;以及通过HTTP POST自动提交监控数据到服务器。Lua的简洁语法和强大功能简化了网络管理和自动化任务。
114 3
|
6月前
|
数据挖掘 Linux 数据处理
探索Linux下的Lua命令:轻量级脚本语言在数据处理和分析中的应用
**探索Linux上的Lua:轻量级脚本语言用于数据处理。Lua通过命令行解释器执行,适用于游戏开发、数据分析及自动化。特点包括小巧、高效、可扩展和动态类型。使用`lua`或`luajit`,配合-e、-l、-i参数执行脚本或互动模式。示例:执行`hello.lua`脚本打印"Hello, Lua!"。最佳实践涉及版本兼容、性能优化、使用C API、测试和文档编写。**
|
6月前
|
JSON 监控 数据格式
使用Lua代码扩展上网行为管理软件的脚本功能
本文介绍了如何使用Lua脚本增强上网行为管理,包括过滤URL、记录用户访问日志、控制带宽和自动提交监控数据到网站。Lua是一种轻量级语言,适合编写扩展脚本。文中提供多个示例代码,如URL过滤器、用户活动日志记录器和带宽控制器,帮助用户根据需求定制网络管理功能。通过这些示例,用户可以快速掌握Lua在上网行为管理中的应用。
177 4
|
7月前
|
存储 监控 数据管理
Lua代码解析:实现上网行为监管软件的自定义规则引擎
在当今数字化时代,网络安全和数据隐私保护备受关注。为了确保网络安全和合规性,许多组织和机构需要监管和管理其员工或用户的上网行为。为了实现这一目标,开发一款高效的上网行为监管软件至关重要。本文将介绍如何使用Lua语言开发一种自定义规则引擎,以实现上网行为监管软件的自定义规则引擎。
226 0
|
运维 5G Go
Go或者C中调用Lua业务脚本,实现终端应用的热更新方案
Go或者C中调用Lua业务脚本,实现终端应用的热更新方案
|
XML Java 数据格式
【Lua基础 第3章】变量、赋值语句、索引、lua中的循环、循环控制语句
lua 中的变量、赋值语句、索引、lua中的循环、循环控制语句
167 0
【Lua基础 第3章】变量、赋值语句、索引、lua中的循环、循环控制语句
|
消息中间件 数据采集 Java
Lua集成kafka第三方插件代码介绍|学习笔记
快速学习Lua集成kafka第三方插件代码介绍
Lua集成kafka第三方插件代码介绍|学习笔记