最新要闻
- 女子买1根牛肉干店员偷塞5根的量 当事人:特别气愤
- 世界今头条!六个口味 八喜冰淇淋3.8元/杯抄底(商超8元)
- 堆料不留遗憾的满血顶级非公旗舰!索泰RTX 4090 PGF OC评测:当之无愧新一代卡皇-世界头条
- 银河证券:通信+新基建板块有望率先预期上修 高景气度结合低估值是选股重点方向
- 我找到了阅读GitHub项目源码的最佳姿势,太舒服了!
- 世界短讯!玩游戏怎么选显示器?认准这几点准没错
- 男子发现捡回家两年的石头是文物 已无偿捐赠:网友惊叹
- 全球热推荐:国产GPU能否满足ChatGPT算力要求 景嘉微回应来了:还不行
- 环球观焦点:今年“蒸煮模式”咋提前了?专家解读
- 长城汽车给理想汽车起了个外号:“微博之王” 李想本人回应亮了 世界微动态
- 易宝支付总裁余晨出席《通用人工智能》新书发布会
- 世界今热点:对建造清代故宫影响最大的工匠,原来是这一家人!
- 合资品牌的无奈!奥迪之后丰田挂牌:我们也有纯电动请往里进
- 苹果Mac OS被指碰瓷WinXP经典壁纸:还真不是玩笑
- 世界快资讯:年轻人压力较大 乘联会崔东树:中国车市还得指望中老年人
- 又一新能源车企被申请破产!曾被称为“四小龙”之一
手机
iphone11大小尺寸是多少?苹果iPhone11和iPhone13的区别是什么?
警方通报辅警执法直播中被撞飞:犯罪嫌疑人已投案
- iphone11大小尺寸是多少?苹果iPhone11和iPhone13的区别是什么?
- 警方通报辅警执法直播中被撞飞:犯罪嫌疑人已投案
- 男子被关545天申国赔:获赔18万多 驳回精神抚慰金
- 3天内26名本土感染者,辽宁确诊人数已超安徽
- 广西柳州一男子因纠纷杀害三人后自首
- 洱海坠机4名机组人员被批准为烈士 数千干部群众悼念
家电
Lua 中如何实现继承
本文主要参考了菜鸟教程中的 Lua 面向对象,再加上自己学习过程的中思考,特此记录,如果文中有不对的地方,请不吝赐教。
这里就不在介绍面向对象的基本思想了,主要讲一讲 Lua 中如何实现继承,包括单继承和多继承
。
1、如何定义一个类
我们知道,对象由属性和方法
组成。Lua 中最基本的结构是table
,所以需要用 table 来描述对象的属性。
(资料图)
Lua 中的 function 可以用来表示方法。那么 Lua 中的类可以通过table + function 模拟出来
。
那我们需要的继承,可以通过 metetable
模拟出来(不推荐用,只模拟最基本的对象大部分实现够用了)。
Lua 中的 table 不仅在某种意义上是一种对象
。既可以像对象一样,有自己的状态(成员变量)。同时也有与对象的值独立的本性
,特别是拥有两个不同值的对象(table)代表两个不同的对象;一个对象在不同的时候也可以有不同的值,但他始终是一个对象;与对象类似,表的生命周期与其由什么创建、在哪创建没有关系。对象有他们的成员函数,表也有。
这段话是看懵逼了,说下自己的理解吧,不对的话,欢迎评论区指出,十分感谢。
这段话主要在介绍 Lua 中的表(table)与对象的相似之处。表不仅仅是一种数据结构,它也有状态(成员变量),并且每个表都是独立的,即使两个表的值相同,它们也代表两个不同的对象。与对象类似,表也有生命周期,与其创建方式和创建位置无关。此外,表也有成员函数,可以通过函数来操作表的数据。
先提一嘴,下面的 new 方法是自定义的,并不是规定必须这样做,写成 abc 都是可以的。
-- 元类Shape = {area = 0}-- 基础类方法 newfunction Shape:new (o,side) o = o or {} setmetatable(o, self) self.__index = self side = side or 0 self.area = side*side; return oend-- 基础类方法 printAreafunction Shape:printArea () print("面积为 ",self.area)end-- 创建对象myshape = Shape:new(nil,10)myshape:printArea()
上面的方式在创建对象时,需要手动传入 nil 参数,不太优雅,我们可以对其进行封装。
--创建一个类,表示四边形local RectAngle = { length, width, area } --声明类名和类成员变量 function RectAngle: new (len,wid) --声明新建实例的New方法local o = {--设定各个项的值 length = len or 0, width = wid or 0, area =len*wid}setmetatable(o,{__index = self} )--将自身的表映射到新new出来的表中return oendfunction RectAngle:getInfo()--获取表内信息的方法return self.length,self.width,self.areaenda = RectAngle:new(10,20)print(a:getInfo()) -- 输出:10 20 200b = RectAngle:new(10,10)print(b:getInfo()) -- 输出:10 10 100print(a:getInfo()) -- 输出:10 20 200
上面 就是 把 变量 o 的创建时候,放到了函数里面而已,并没特别的地方,但是可以省去我们调用时每次都需要传 nil 的麻烦。
2、前置知识
在学习如何使用 Lua 实现继承之前,我们先来学习几个 Lua 的基本知识,为后面的继承打下基础。
- table
- Metatable
2.1 table 的简单介绍
下面看看如何初始化表
-- 初始化 表Stu1 = {age=10, sex=1}-- 指定值Stu1["name"] = "xiaoming"-- 添加方法function Stu1:getSex()return self.sexendfunction Stu1:getName()return Stu1.nameendprint(Stu1["name"]) -- xiaomingprint(Stu1["age"]) -- 10print(Stu1.age) -- 10 print(Stu1:getSex()) -- 1-- print(Stu1["getSex"]()) 报错print(Stu1["getName"]()) -- xiaoming
对于上面不清楚的同学,可以看看我之前写的 lua中 . 和 : 的区别 这篇文章。
2.2 Metatable
下面的内容都是来自 Lua 元表(Metatable)
在 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)。
以下实例演示了如何对指定的表设置元表:
mytable = {} -- 普通表mymetatable = {} -- 元表setmetatable(mytable,mymetatable) -- 把 mymetatable 设为 mytable 的元表
以上代码也可以直接写成一行:
mytable = setmetatable({},{})
以下为返回对象元表:
getmetatable(mytable) -- 这会返回 mymetatable
3.2.1 __index 元方法
这是 metatable 最常用的键。
当你通过键来访问 table 的时候,如果这个键没有值,那么Lua就会寻找该table的metatable(假定有metatable)中的__index
键。如果__index
包含一个表格,Lua会在表格中查找相应的键。
我们可以在使用 lua 命令进入交互模式查看:
$ luaLua 5.3.0 Copyright (C) 1994-2015 Lua.org, PUC-Rio> other = { foo = 3 }> t = setmetatable({}, { __index = other })> t.foo3> t.barnil
如果__index
包含一个函数的话,Lua就会调用那个函数,table和键会作为参数传递给函数
(这句话很重要,后面的多重继承就使用到了这个原理)。
__index
元方法查看表中元素是否存在,如果不存在,返回结果为 nil;如果存在则由__index
返回结果。
mytable = setmetatable({key1 = "value1"}, { __index = function(mytable, key) if key == "key2" then return "metatablevalue" else return nil end end})print(mytable.key1,mytable.key2)
实例输出结果为:
value1 metatablevalue
实例解析:
mytable 表赋值为 {key1 = "value1"}。
mytable 设置了元表,元方法为 __index。
在mytable表中查找 key1,如果找到,返回该元素,找不到则继续。
在mytable表中查找 key2,如果找到,返回 metatablevalue,找不到则继续。
判断元表有没有__index方法,如果__index方法是一个函数,则调用该函数。
元方法中查看是否传入 "key2" 键的参数(mytable.key2已设置),如果传入 "key2" 参数返回 "metatablevalue",否则返回 mytable 对应的键值。
我们可以将以上代码简单写成:
mytable = setmetatable({key1 = "value1"}, { __index = { key2 = "metatablevalue" } })print(mytable.key1,mytable.key2)
总结:
Lua 查找一个表元素时的规则,其实就是如下 3 个步骤:
- 1.在表中查找,如果找到,返回该元素,找不到则继续
- 2.判断该表是否有元表,如果没有元表,返回 nil,有元表则继续。
- 3.判断元表有没有
__index
方法,如果__index
方法为 nil,则返回 nil;如果__index
方法是一个表,则重复 1、2、3;如果__index
方法是一个函数,则返回该函数的返回值。
3、单继承
当我们学习了 Lua 中如何定义一个类后,就可以考虑,如何在 Lua 中实现单继承了。接下来,我们一起看看如何实现单继承。
-- 元类local Base = {}-- 基础类方法 newfunction Base:new(name)local o = {name = name or "default"}--将自身的表映射到新new出来的表中setmetatable(o, self)self.__index = self return oendfunction Base:run()print(self.name .. " is running....")end-- 创建对象b = Base:new("Base")b:run()print(string.rep("*", 30))-- 创建派生类对象-- 重点理解这里为何需要这样初始化对象,而不能像这样 T3 = {} 初始化变量 T3-- 原因就在于 T3:new() 中 self 变量就是 T3 这个变量,当使用 setmetseatable、__index 时,才会给-- T3:new() 中的变量o 添加上 Base 定义的属性和方法。T3 = Base:new()-- 派生类方法 newfunction T3:new(name)-- 实现继承,这里实现继承不仅仅是靠下面这一句实现的-- 而是 加上 setmetatable、__index 才模拟出 继承的现象local o = Base:new(name)setmetseatable(o, self)self.__index = selfreturn oendlocal t3 = T3:new("T3")t3:run()print(string.rep("*", 30))-- 创建派生类对象BYD = Base:new()-- 派生类方法 newfunction BYD:new(name)-- 实现继承,这里实现继承不仅仅是靠下面这一句实现的-- 而是 加上 setmetatable、__index 才模拟出 继承的现象local o = Base:new(name)setmetatable(o, self)self.__index = selfreturn oend-- 派生类创建方法function BYD:power()print(self.name .. " 正在充电.....")endlocal byd = BYD:new("BYD")byd:run()byd:power()print(string.rep("*", 30))
运行结果:
Base is running....******************************T3 is running....******************************BYD is running....BYD 正在充电.....******************************
从上面可以看到,T3、BYD 这两个类 继承 了 Base 类的 run 方法。
4、多继承
4.1 线性多重继承
A1 = {}function A1:new(name)local o = {name = name or "A1"}setmetatable(o, {__index = self})return oendfunction A1:printA1()print(self.name .. "is coming printA1")end-- 重点理解这里为何需要这样定义,而不能 A2 = {} 这样初始化变量 A2A2 = A1:new()function A2:new(name)-- 这样就可以继承A1定义的方法local o = A1:new(name) setmetatable(o, {__index = self})return oendfunction A2:printA2()print(self.name .. "is coming printA2")endA3 = A2:new()function A3:new(name)local o = A2:new(name)setmetatable(o, {__index = self})return oendfunction A3:printA3()print(self.name .. "is coming printA3")end-- 创建对象a = A3:new("I"m a ")a:printA1()a:printA2()a:printA3()
运行结果:
I"m a is coming printA1I"m a is coming printA2I"m a is coming printA3
上面这种方法,是比较容易想到的实现多重继承的方式,但是这种方式有一定的局限性,继承不够灵活。下面再来看看另外一种继承方式,相当而言就会灵活很多。
4.2 更加灵活的多重继承
-- 在 table 变量 cList 中查找 klocal function search(k, cList)for i=1,#cList dolocal v = cList[i][k]-- 尝试第i个基类if v thenreturn vendendendfunction createClass(...)local c = {}print("c 的地址 -->", c)local parents = {...}-- 类在其父类列表中的搜索方法 setmetatable(c, {__index = function(t, k)-- 这里传入的 t 就是 刚刚定义的 c-- 如果__index包含一个函数的话,Lua就会调用那个函数,table和键会作为参数传递给函数。-- __index 元方法查看表中元素是否存在,如果不存在,返回结果为 nil;如果存在则由 __index 返回结果。print("t 的地址 -->", t)print("k -->", 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-- 类NamedNamed = {}function Named:getname() return self.nameendfunction Named:setname(n) self.name = nend-- 类AccountAccount = {balance = 0}function Account:withdraw(w) self.balance = self.balance - wendprint("Account -->", Account["withdraw"])-- 创建一个新类NamedAccount,同时从Account和Named派生NamedAccount = createClass(Account, Named)account = NamedAccount:new()account:setname("Ives")print(account:getname()) -- 输出 Ivesaccount:withdraw(10)print(account.balance)
运行结果:
Account["withdraw"] --> function: 039BD710c 的地址 --> table: 039BB7E8t 的地址 --> table: 039BB7E8k --> setnamet 的地址 --> table: 039BB7E8k --> getnameIvest 的地址 --> table: 039BB7E8k --> withdrawt 的地址 --> table: 039BB7E8k --> balance-10
参考资料:
Lua 面向对象
关键词:
Lua 中如何实现继承
女子买1根牛肉干店员偷塞5根的量 当事人:特别气愤
世界今头条!六个口味 八喜冰淇淋3.8元/杯抄底(商超8元)
堆料不留遗憾的满血顶级非公旗舰!索泰RTX 4090 PGF OC评测:当之无愧新一代卡皇-世界头条
银河证券:通信+新基建板块有望率先预期上修 高景气度结合低估值是选股重点方向
记录--封装一个通过js调用的全局vue组件
世界讯息:Linux下常用命令
vim敲字如弹琴
我找到了阅读GitHub项目源码的最佳姿势,太舒服了!
世界短讯!玩游戏怎么选显示器?认准这几点准没错
男子发现捡回家两年的石头是文物 已无偿捐赠:网友惊叹
全球热推荐:国产GPU能否满足ChatGPT算力要求 景嘉微回应来了:还不行
环球观焦点:今年“蒸煮模式”咋提前了?专家解读
长城汽车给理想汽车起了个外号:“微博之王” 李想本人回应亮了 世界微动态
易宝支付总裁余晨出席《通用人工智能》新书发布会
腾讯太狠:40亿QQ号, 给你1G内存,怎么去重?
天天热点评!ASP.NET Core MVC 从入门到精通之Identity入门
世界今热点:对建造清代故宫影响最大的工匠,原来是这一家人!
合资品牌的无奈!奥迪之后丰田挂牌:我们也有纯电动请往里进
苹果Mac OS被指碰瓷WinXP经典壁纸:还真不是玩笑
世界快资讯:年轻人压力较大 乘联会崔东树:中国车市还得指望中老年人
又一新能源车企被申请破产!曾被称为“四小龙”之一
珠碱商品报价动态(2023-06-17)
看点:只需4年 PCIe 7.0硬盘有望追上DDR5内存:性能狂飙
人不在学校却被抬到校长面前拨穗 全场欢呼鼓掌:不想让舍友留下遗憾
嫌榴莲太臭?可它这3个好处“香”到不行!
《闪电侠》豆瓣8分:超七成观众给出4星以上好评
生来上等命,前有贵人,后有靠山,注定好运不断的星座,日后必成大器
3999元起 蔚来天穹车尾帐发布:10分钟快速搭建“一室一厅”
腾讯、网易游戏公布端午未成年人限玩时间:高考后准大学生仍被限
天天快看:中国车第一次!领克03高性能特别版首发:原厂防滚架可上路
酷睿i9-13700H VS.锐龙9 7940H全面对比:AMD仍有很长的路要走
天天热推荐:布林肯冀访华改善中美沟通避免引发冲突 中方促美尊重核心关切
今日热门!分心驾驶致5人身亡 家属质疑10个气囊全未弹开 丰田销售:后方撞击不能触发
深圳邮局海关查获23只外来毒虫!内含秘鲁巨人蜈蚣 天天通讯
宣布对西安工厂投资43亿元:消息称美光也要向印度投资10亿美元
韩方曝出:福岛核污水超标2万倍
比小米便宜一半!TCL雷鸟Mini LED电视85英寸只要7599元 焦点简讯
理想L7/8/9魔毯空气悬挂2.0实测:防刹车点头来了 _环球滚动
GPT-4满分通过MIT本科数学考试!这套提示词火了
看热讯:10万出头续航505km 江淮钇为3上市:打的就是比亚迪海豚
不靠高精地图!小鹏汽车演示北京无图区智能辅助驾驶:稳如老司机_全球今亮点
Android-JNI开发概论-动态
鲍威尔_1937~_关于鲍威尔_1937~简述_消息
全球今日讯!华为NCA智能驾驶来了!余承东:超越特斯拉FSD 这15个城市率先体验
vivo X90s跑分出炉:165万安卓性能天花板!领先20万-全球实时
从泰山弃将到亚泰宠儿,莱昂纳多逆袭霸榜,机会总留给有准备的人-每日速递
软件开发人员必须阅读的20本书_每日速看
快资讯丨语音社交源码知识语音房间功能的实现
《安富莱嵌入式周报》第315期:开源USB高速分析仪,8GHz示波器开发, 600行C编写RISC-V内核,英特尔推出用于开发人员等宽字体,便携物联网监测器_
韩国出现地产危机房价暴跌近20%?可以“免费住”的全租房模式暗藏风险
网友吐槽“高考后还要被防沉迷” :腾讯游戏官方高情商回应
8粽+4咸蛋21元:五芳斋旗下端午礼盒大促
美司法部申请保护令动议,要求阻止特朗普公开机密文件
上周纯碱期价有所下跌
从《闪电侠》到《蝙蝠侠》
货车撞上奔驰反被奔驰车主请吃饭 对方生活不易:网友点赞
比亚迪杀进法拉利、兰博基尼老家:BYD ATTO 3、汉、海豚、海豹正式进军意大利|头条
村民深夜失足坠崖 酉阳民警紧急救援 环球头条
俄方称将重提“北溪”管道遭破坏事件调查话题
iOS 17淘汰iPhone 8、X等:苹果老机型贬值率激增-滚动
环球动态:张雪峰回应质疑:大学专业要选能吃上饭的 要为自己负责
【报资讯】6月16日基金净值:鹏华环保产业股票最新净值3.987,涨1.71%
每日聚焦:马云近况曝光:在东京教书 与大学生合影 与汪涵聚餐发福变胖
开始担心被“抢饭碗”了:越南打工人不加班逼急中国老板 不为钱放弃生活
焦点信息:1314玫瑰小镇魔法花园 1314玫瑰小镇登录
读数据压缩入门笔记06_上下文转换_速看
【环球新要闻】泡泡玛特4r出透卡什么意思 泡泡玛特几r出透什么意思
天天观热点:Polly简单使用
go语言list表
北京警方依法行政拘留冲入球场拥抱梅西的球迷
女子拆145个盲盒拒付款!父亲称其有精神病闹上法庭:结果出来了
每日观察!电影《消失的她》预售票房破千万:陈思诚监制 倪妮主演
广东暴雨积水成河:有人屋内钓鱼 有人"水上摩托"
每日播报!不再依赖进口 国产磁共振医疗装备重大突破:绰号“白胖子”
天天观点:未通过网络安全审查 禁止采购!美光宣布在中国投资超43亿元
6月16日基金净值:景顺长城远见成长混合A最新净值1.1679,涨2.43% 要闻速递
2023高考英语作文预测热门话题_2018热门话题新闻作文100字
每日看点!iso怎么转换为gho_怎样才能把ISO文件转换成GHO文件 1111
Kotlin协程-从理论到实战
常见WebShell的流量特征
今日报丨01. 组建知识星球服务体系
嵩山少林塔沟武校学费_嵩山少林塔沟武校
《云顶之弈》网页版云游戏上线:PC互通 手机点开就能玩
环球快资讯丨最美“小丑女”演女主!《芭比》真人电影国内定档:7月21日上映
环球今头条!玩家哭了!女子带100张《塞尔达传说:王国之泪》卡带入境被海关查获
一之濑拓实和小松奈奈第一次见面(一之濑拓实)_天天快消息
今日视点:美股盘初:Adobe涨约5%,维珍银河涨超45%
普通人也能太空旅行 我国将推出商业航天项目:最快5年后|全球要闻
世界时讯:阿里总裁谈马云近况:他在东京教书 很开心
资讯:奥运冠军苏翊鸣获得清华大学保送资格 发文感谢:18岁三个愿望都实现了
法官曼司亚:一起离婚案件她跟踪回访了12年
当前关注:聊聊Flink必知必会(四)
【世界快播报】Kotlin协程-从一到多
金科地产8.8亿元债券本息未按期偿付 持有人会议仍在表决中 新动态
向佐晒儿子周岁宴,现场紧搂郭碧婷秀恩爱,儿女露正脸都是高颜值_快资讯
江淮钇为3上市:最长续航600公里、8.99万元起_天天资讯
酷睿Ultra来了!Intel史上最混乱一代 还有马甲
谨慎下载 Win10 ISO镜像被黑客下马:攻击手法罕见_环球热消息
报道:博尔特4x100