Lua中利用元表实现类和多态教程
0基础lua学习(十六)lua的多态base
0基础lua学习(⼗六)lua的多态base 多态base使⽤lua实现C++类似的多态,看起来略微难了⼀些,这个demo,默认提供了 init类似构造函数的时机。
--base.lua代码--保存类类型的虚表local _class = {}function BaseClass(super)-- ⽣成⼀个类类型local class_type = {}-- 在创建对象的时候⾃动调⽤class_type.__init = falseclass_type.__delete = falseclass_type.super = superclass_type.New = function(...)-- ⽣成⼀个类对象local obj = {}obj._class_type = class_type-- 在初始化之前注册基类⽅法setmetatable(obj, { __index = _class[class_type] })-- 调⽤初始化⽅法dolocal createcreate = function(c, ...)if c.super thencreate(c.super, ...)endif c.__init thenc.__init(obj, ...)endendcreate(class_type, ...)end-- 注册⼀个delete⽅法obj.DeleteMe = function(self)local now_super = self._class_typewhile now_super ~= nil doif now_super.__delete thennow_super.__delete(self)endnow_super = now_super.superendendreturn objendlocal vtbl = {}_class[class_type] = vtblsetmetatable(class_type, {__newindex =--table key valuefunction(t,k,v)vtbl[k] = vend,__index = vtbl, --For call parent method})if super thensetmetatable(vtbl, {__index =function(t,k)local ret = _class[super][k]return retend})endreturn class_typeend--main.lua代码require"base"father = father or BaseClass()function father:__init()print("father:init")endfunction father:Bind()print("father:Bind")endfunction father:play()print("father:play")endson = son or BaseClass(father)function son:__init()print("son:init")endfunction son:Bind()print("son:Bind")endfunction son:UnBind()enda = nila = son:New()a:play()a:Bind()console:father:initson:initfather:playson:Bind多态base解析1.⾸先要明确father = father or BaseClass( )和 son = son or BaseClass(father)有⼀个共同的表local _class = {},也就是虚表。
Lua教程(九):元表与元方法详解
Lua教程(九):元表与元⽅法详解Lua中提供的元表是⽤于帮助Lua数据变量完成某些⾮预定义功能的个性化⾏为,如两个table的相加。
假设a和b都是table,通过元表可以定义如何计算表达式a+b。
当Lua试图将两个table相加时,它会先检查两者之⼀是否有元表,然后检查该元表中是否存在__add字段,如果有,就调⽤该字段对应的值。
这个值就是所谓的“元⽅法”,这个函数⽤于计算table的和。
Lua中每个值都有⼀个元表。
table和userdata可以有各⾃独⽴的元表,⽽其它数据类型的值则共享其类型所属的单⼀元表。
缺省情况下,table在创建时没有元表,如:复制代码代码如下:t = {}print(getmetatable(t)) --输出为nil这⾥我们可以使⽤setmetatable函数来设置或修改任何table的元表。
复制代码代码如下:t1 = {}setmetatable(t,t1)assert(getmetatable(t) == t1)任何table都可以作为任何值的元表,⽽⼀组相关的table也可以共享⼀个通⽤的元表,此元表将描述了它们共同的⾏为。
⼀个table甚⾄可以作为它⾃⼰的元表,⽤于描述其特有的⾏为。
在Lua代码中,只能设置table的元表,若要设置其它类型值的元表,则必须通过C代码来完成。
1. 算术类的元⽅法:在下⾯的⽰例代码中,将⽤table来表⽰集合,并且有⼀些函数⽤来计算集合的并集和交集等。
复制代码代码如下:Set = {}local metatable = {} --元表--根据参数列表中的值创建⼀个新的集合function Set.new(l)local set = {}--将所有由该⽅法创建的集合的元表都指定到metatablesetmetatable(set,metatable)for _, v in ipairs(l) doset[v] = trueendreturn setend--取两个集合并集的函数function Set.union(a,b)local res = Set.new{}for k in pairs(a) dores[k] = trueendfor k in pairs(b) dores[k] = trueendreturn resend--取两个集合交集的函数function Set.intersection(a,b)local res = Set.new{}for k in pairs(a) dores[k] = b[k]endreturn resendfunction Set.tostring(set)local l = {}for e in pairs(set) dol[#l + 1] = eendreturn "{" .. table.concat(l,", ") .. "}";endfunction Set.print(s)print(Set.tostring(s))end--最后将元⽅法加⼊到元表中,这样当两个由Set.new⽅法创建出来的集合进⾏--加运算时,将被重定向到Set.union⽅法,乘法运算将被重定向到Set.intersectionmetatable.__add = Set.unionmetatable.__mul = Set.intersection--下⾯为测试代码s1 = Set.new{10,20,30,50}s2 = Set.new{30,1}s3 = s1 + s2Set.print(s3)Set.print(s3 * s1)--输出结果为:--{1, 30, 10, 50, 20}--{30, 10, 50, 20}在元表中,每种算术操作符都有对应的字段名,除了上述的__add(加法)和__mul(乘法)外,还有__sub(减法)、__div(除法)、__unm(相反数)、__mod(取模)和__pow(乘幂)。
lua高级用法
lua高级用法
Lua的高级用法包括但不限于以下几个方面:
1. 表(table)的高级使用:表是Lua中的核心数据结构,具有灵活性和可变性。
你可以使用表进行类数组的操作,通过默认的索引进行访问;还可以使用特定的方法获取或改变表的长度;更可以利用for循环和pairs函数遍历表中的元素。
2. 函数(function)的高级定义和使用:Lua允许使用函数进行模块化和重用,你还可以使用闭包(closure)来创建私有函数。
3. 协程(coroutine):协程是一种程序组件,它可以在执行过程中挂起,并在以后从挂起点继续执行。
Lua提供了对协程的支持,你可以用它实现异步编程。
4. 错误处理:Lua提供了简单的错误处理机制,你可以使用try/catch语句来捕获和处理错误。
5. 高级I/O:Lua提供了一套完整的I/O库,支持文件和流的读写操作。
6. 自定义数据类型:Lua允许你通过创建新的表作为自定义的数据类型,以扩展或修改现有的数据类型。
7. 元表(metatable):元表提供了一种方式来定义对象的行为。
你可以通过元表来修改或扩展已有的数据类型。
以上只是Lua高级用法的一部分,具体的使用方式会因你的需求和场景而有所不同。
lua 元表和元方法
if type(table) == "table" then
local v = rawget(table, key)
if v ~= nil then
return v
end
h = metatable(table).__index
metatable(obj)[event]
它应被解读为
rawget(getmetatable(obj) or {}, event)
就是说,访问一个元方法不会调用其他元方法,而且访问没有元表的对象不会失败(只是结果为nil)。
"add": + 操作。
下面的getbinhandler函数定义Lua如何选择二元操作的处理程序。首先尝试第一操作数,如果它的类型没有定义该操作的处理程序,则尝试第二操作数。
if type(op1) == "number" and type(op2) == "number" then
return op1 < op2 -- 数字比较
elseif type(op1) == "string" and type(op2) == "string" then
end
end
end
a > b等价于b < a。
"le": <= 操作。
function le_event (op1, op2)
if type(op1) == "number" and type(op2) == "number" then
return op1 <= op2 -- 数字比较
lua程序设计 10章
lua程序设计 10章(最新版)目录1.Lua 程序设计的概述2.Lua 语言基础3.控制结构4.函数和模块5.表和元表6.迭代和递归7.集合和散列8.输入输出和错误处理9.面向对象编程10.GPU 编程和扩展库正文Lua 程序设计是一本关于 Lua 编程语言的书籍,全书共分为 10 章,涵盖了 Lua 编程的方方面面。
第一章,Lua 程序设计的概述,主要介绍了 Lua 编程语言的发展历程,特点以及应用领域。
Lua 作为一种轻量级的脚本语言,广泛应用于游戏开发、嵌入式系统、Web 开发等领域。
第二章,Lua 语言基础,主要介绍了 Lua 的基本语法,包括变量、常量、运算符、类型等。
第三章,控制结构,主要介绍了 Lua 的控制结构,包括条件语句、循环语句等。
第四章,函数和模块,主要介绍了 Lua 的函数定义和调用,以及模块的导入和使用。
第五章,表和元表,是 Lua 的核心数据结构,表是 Lua 的一种有序集合,元表是表的一种扩展,可以用来定义表的属性和操作。
第六章,迭代和递归,主要介绍了 Lua 的迭代和递归机制,包括 for 循环、while 循环以及递归函数的定义和调用。
第七章,集合和散列,主要介绍了 Lua 的集合数据结构和散列函数,集合是一种无序的元素集合,散列函数可以用来对集合进行快速查找和插入操作。
第八章,输入输出和错误处理,主要介绍了 Lua 的输入输出函数以及错误处理的机制。
第九章,面向对象编程,主要介绍了 Lua 的面向对象编程机制,包括类、对象、继承、多态等。
第十章,GPU 编程和扩展库,主要介绍了如何使用 Lua 进行 GPU 编程,以及如何使用 Lua 扩展库进行各种操作。
Lua面向对象(实现类的创建和实例化、封装、继承、多态)
Lua⾯向对象(实现类的创建和实例化、封装、继承、多态)⽬录1、Lua⾯向对象基础⾯向对象三⼤特性包括:封装、继承、多态。
还有在Lua中如何创建类和实例化,这⾥⼀⼀介绍1.1、Lua类的创建和实例化Test1.lua--name,age就相当于字段。
eat就相当于⽅法person = {name = 'Ffly',age = 20}function person:eat()print( .. '该吃饭饭了,饿死了')end--这个⽅法⽤于实例化使⽤function person:new()local self = {}--使⽤元表,并把__index赋值为person类setmetatable(self,{__index = person})return selfendTest2.lua--加载模块Test1.lua(类似于C#中的using引⽤)--LuaStudio默认从软件根⽬录下加载require "Test1"--实例化person类person1 = person:new()person1:eat() --正常输出1.2、Lua封装--对age字段进⾏封装,使其只能⽤get⽅法访问function newPerson(initAge)local self = {age = initAge};--三个⽅法local addAge = function(num)self.age = self.age + num;endlocal reduceAge = function(num)self.age = self.age - num;endlocal getAge = function(num)return self.age;end--返回时只返回⽅法return {addAge = addAge,reduceAge = reduceAge,getAge = getAge,}endperson1 = newPerson(20)--没有使⽤额外的参数self,⽤的是那⾥⾯的self表--所以要⽤.进⾏访问person1.addAge(10)print(person1.age) --输出nilprint(person1.getAge()) --输出301.3、Lua继承--基类person,boy类继承于personperson = {name = "default",age = 0}function person:eat()print( .. '该吃饭饭了,饿死了')end--使⽤元表的 __index完成继承(当访问不存在的元素时,会调⽤)function person:new(o)--如果o为false或者o为nil,则让o为{}o = o or {}setmetatable(o,self)--设置上⾯self的__index为表personself.__index = selfreturn oend--相当于继承boy = person:new()--name在boy⾥找不到会去person⾥⾯找print() --输出default--修改了person⾥的值,并不会影响boy⾥⾯的值 = 'feifei'print() --输出defaultprint() --输出feifei1.4、Lua多态person = {name = "default",age = 0}--重载--简单⽅法:lua中会⾃动去适应传⼊参数的个数,所以我们可以写在⼀个⽅法⾥⾯function person:eat(food)if food == nil thenprint( .. '该吃饭饭了,饿死了')elseprint( .. '喜欢吃:' .. food)endendfunction person:addAge(num)if num == nil thenself.age = self.age + 1elseself.age = self.age + numendendprint(person:eat())print(person:eat("⼤西⽠"))person:addAge()print(person.age)person:addAge(5)print(person.age)--重写function person:new(o)--如果o为false或者o为nil,则让o为{}o = o or {}setmetatable(o,self)--设置上⾯self的__index为表personself.__index = selfreturn oendboy = person:new() = "Ffly"boy:eat() --调⽤基类eat⽅法--相当于重写eat⽅法function boy:eat()print('⼩男孩' .. .. '快要饿死了')endboy:eat() --调⽤派⽣类eat⽅法2、Lua⾯向对象进阶2.1、class.lua的实现class代码参考于的博客。
lua绑定C++对象系列四——luna模板
lua绑定C++对象系列四——luna模板在系列⽂章⼆三中描述的绑定C++对象基础篇和进阶篇,都有⼀个很⼤的问题,就是每个类需要写⼤量的代码,从类的元表创建、⽅法注册到实例创建,都需要⾃⼰重复写类似的代码。
如果涉及N个不同类,会有⼤量重复的代码,能否创建⼀个模板类,把这些重复的代码进⾏简化,通过模板的⽅式绑定成不同的类?下⾯的luna<T>就是完成这样⼀个壮举,例如针对Car类,只需要luna<Car>::regist(L)即可完成注册。
在lua层⾯ local car = Car()就能⾃动创建Car对象,然后⽅便的通过car.xxx()调⽤成员⽅法。
代码⽂件luna.h1 #include <iostream>2 #include <cstring>3extern"C" {4 #include <lua.h>5 #include <lualib.h>6 #include <lauxlib.h>7 }89using namespace std;1011#define DECLARE_LUNA_CLASS(obj) \12static const char *name;\13static luna<obj>::TMethod methods[];1415#define EXPORT_LUNA_FUNCTION_BEGIN(obj) \16const char* obj::name = #obj;\17 luna<obj>::TMethod obj::methods[] = {1819#define EXPORT_LUNA_MEMBER_INT(obj, member) \20 {#member, nullptr},2122#define EXPORT_LUNA_FUNCTION(obj, func) \23 {#func, &obj::func},2425#define EXPORT_LUNA_FUNCTION_END(obj) \26 {nullptr, nullptr}\27 };2829 template<typename T>30class luna31 {32public:33 typedef struct {T* _u;} TObject;34 typedef int (T::*TPfn)(lua_State* L);35 typedef struct {const char* name; TPfn pf;} TMethod;36public:37static int regist(lua_State* L);38static int create(lua_State* L);39static int call(lua_State* L);40static int gc(lua_State* L);41 };4243 template<typename T>44int luna<T>::regist(lua_State* L)45 {46//原表Shape47if (luaL_newmetatable(L, T::name))48 {49//注册Shape到全局50 lua_newtable(L);51 lua_pushvalue(L, -1);52 lua_setglobal(L, T::name);5354//设置Shape的原表,主要是__call,使其看起来更像C++初始化55 lua_newtable(L);56 lua_pushcfunction(L, luna<T>::create);57 lua_setfield(L, -2, "__call");58 lua_setmetatable(L, -2);59 lua_pop(L, 1); //这时候栈只剩下元表61//设置元表Shape index指向⾃⼰62 lua_pushvalue(L, -1);63 lua_setfield(L, -2, "__index");64 lua_pushcfunction(L, luna<T>::gc);65 lua_setfield(L, -2, "__gc");66 }67return0;68 }6970 template<typename T>71int luna<T>::create(lua_State* L)72 {73 lua_remove(L, 1);74 TObject* p = (TObject*)lua_newuserdata(L, sizeof(TObject));75 p->_u = new T();7677 luaL_getmetatable(L, T::name);78 lua_setmetatable(L, -2);7980 luaL_getmetatable(L, T::name);81for (auto* l = T::methods; l->name; l++)82 {83 lua_pushlightuserdata(L,(void*)l);84 lua_pushlightuserdata(L,(void*)p);85 lua_pushcclosure(L, luna<T>::call, 2);86 lua_setfield(L, -2, l->name);87 }8889 lua_pop(L, 1);9091return1;92 }9394 template<typename T>95int luna<T>::call(lua_State* L)96 {97 TMethod* v = (TMethod*)lua_topointer(L, lua_upvalueindex(1));98 cout<<"luna<T>::call:"<<v->name<<endl;99100 TObject* p = (TObject*)lua_topointer(L, lua_upvalueindex(2));101102103return ((p->_u)->*(v->pf))(L);104 }105106 template<typename T>107int luna<T>::gc(lua_State* L)108 {109 TObject* p = (TObject*)lua_touserdata(L, 1);110 (p->_u)->~T();111return0;112 }通过上述代码发现:luna<T>模板类,把⼀些⾏为固化下来了。
lua 元方法
lua 元方法Lua元方法是Lua语言中的一种特殊机制,它能够让我们通过重载一些特定的操作符来实现自定义的行为,使得我们的代码更加灵活、易于理解和维护。
在本文中,我们将深入探讨Lua元方法的相关概念、使用方法和实际应用场景,帮助读者更好地理解和掌握这一重要的特性。
一、什么是Lua元方法在Lua语言中,元方法是一种特殊的函数,它们与特定的操作符相关联,当执行这些操作符时,Lua会自动调用相应的元方法。
通过重载这些元方法,我们可以改变Lua默认的行为,并实现自定义的操作方式。
例如,我们可以通过重载加号操作符来实现两个表的合并,重载取值操作符来实现自定义的属性访问方式等等。
Lua中的元方法通常以__开头和结尾,例如__add、__index、__newindex等。
这些元方法都是Lua内部预定义的,它们与特定的操作符相关联,当执行这些操作符时,Lua会自动调用相应的元方法。
我们也可以自定义元方法,通过设置元表(metatable)来将自定义的元方法与特定的操作符关联起来。
二、Lua元方法的使用方法Lua元方法的使用方法非常简单,我们只需要定义一个元表,并将元表与需要进行操作的对象关联即可。
例如,我们可以通过如下代码定义一个元表:```lualocal mt = {}```然后,我们可以通过设置元表来将元表与某个对象关联起来,例如:```lualocal t = {}setmetatable(t, mt)```这样,当我们对这个对象执行某个操作时,Lua就会自动调用与该操作关联的元方法。
例如,当我们对两个表进行加法操作时,Lua 会自动调用__add元方法来实现加法操作,如果我们定义了自定义的__add函数,就可以改变加法操作的行为。
下面是一些常用的元方法及其对应的操作符:| 元方法 | 操作符 | 说明 || --- | --- | --- || __add | + | 加法操作 || __sub | - | 减法操作 || __mul | * | 乘法操作 || __div | / | 除法操作 || __mod | % | 取模操作 || __pow | ^ | 求幂操作 || __unm | - | 取负操作 || __concat | .. | 连接操作 || __eq | == | 相等操作 || __lt | < | 小于操作 || __le | <= | 小于等于操作 || __index | [] | 取值操作 || __newindex | [] | 赋值操作 || __call | () | 函数调用操作 |通过重载这些元方法,我们可以实现各种自定义的操作行为。
lua 继承析构
lua 继承析构Lua 作为一种脚本语言,其在编程中的应用越来越广泛。
在面向对象编程中,继承和析构是两个重要概念。
本文将介绍如何在Lua 中实现继承和析构,并通过示例代码进行详细解析。
1.Lua 继承概述在Lua 中,继承是通过元表(metatable)实现的。
每一个表(table)都可以有一个元表,通过设置元表,可以实现表的继承。
继承的核心思想是“ is a ”,即子类继承了父类的属性和方法。
2.Lua 析构函数概述析构函数是在对象销毁时执行的自定义函数,用于清理对象资源。
在Lua 中,可以通过定义__destroy__元方法来实现析构函数。
3.实现Lua 继承和析构的方法以下是一个简单的Lua 继承和析构的实现示例:```lua-- 父类local Parent = {}Parent.__index = Parent-- 父类构造函数function Parent:new()local self = setmetatable({}, self)-- 初始化属性 = "parent"return selfend-- 父类析构函数function Parent:destroy()print("Parent destroy")end-- 子类继承父类local Child = {}setmetatable(Child, Parent)Child.__index = Child-- 子类构造函数function Child:new()local self = setmetatable(Parent.new(self), self) -- 初始化属性 = "child"return selfend-- 子类析构函数function Child:destroy()print("Child destroy")-- 调用父类析构函数Parent.destroy(self)end-- 创建对象local parent = Parent:new()local child = Child:new()-- 输出:-- Parent create-- Child create-- Parent destroy-- Child destroy```4.示例代码及解析在上面的示例中,我们定义了一个父类`Parent`和一个子类`Child`。
lua __pairs元方法(一)
lua __pairs元方法(一)__pairs元方法的介绍__pairs元方法的作用•__pairs元方法用于自定义循环一个对象时的行为。
•当我们使用for...in结构来迭代一个对象时,实际上是调用该对象的__pairs元方法来进行遍历。
__pairs元方法的用法__pairs元方法必须返回一个迭代器和初始状态参数,迭代器每次返回一个键值对。
使用如下语法定义__pairs元方法:function myPairs(obj)return function (obj, index)-- 返回下一个键值对end, obj, nilend-- 将myPairs方法赋值给自己定义的对象的__pairs字段myObject.__pairs = myPairs使用__pairs元方法实现不同类型对象的迭代迭代数组一个简单的数组可以通过__pairs方法来进行迭代,示例代码如下:local myArray = {1, 2, 3, 4, 5}-- 定义myArray的__pairs元方法function myArray.__pairs()local index = 0return function (array, index)index = index + 1if array[index] ~= nil thenreturn index, array[index]endend, myArray, indexend-- 使用for循环遍历数组for index, value in pairs(myArray) doprint(index, value)end输出结果:1 12 23 34 45 5迭代自定义对象我们可以通过自定义__pairs元方法来实现对自定义对象的迭代。
示例代码如下:local myObject = {}-- 定义myObject的__pairs元方法function myObject.__pairs()local index = 0return function (object, index)index = index + 1local key = [index]if key ~= nil thenreturn key, object[key]endend, myObject, indexend= {"name", "age", "gender"}= "John"= 25= "Male"-- 使用for循环遍历myObjectfor key, value in pairs(myObject) doprint(key, value)end输出结果:name Johnage 25gender Male迭代自定义迭代器对象我们也可以定义一个迭代器对象,并通过该对象的__pairs元方法来进行迭代。
lua 继承析构
Lua继承析构在Lua中,继承是一种常见的面向对象编程的概念,它允许我们创建新的类并从现有类中继承属性和方法。
同时,析构函数也是面向对象编程中的重要概念,它用于在对象销毁时执行一些清理工作。
本文将详细介绍如何在Lua中实现继承和析构函数。
继承继承是一种通过从现有类派生出新类来共享属性和方法的机制。
在Lua中,我们可以使用元表(metatables)来实现继承。
元表是一种特殊的表,它可以为其他表设置一些特殊的行为。
通过设置元表,我们可以使一个表继承另一个表的属性和方法。
下面是一个示例,演示了如何在Lua中实现继承:-- 父类local Parent = {}function Parent:new()local obj = {}setmetatable(obj, self)self.__index = selfreturn objendfunction Parent:hello()print("Hello from Parent")end-- 子类local Child = Parent:new()function Child:hello()print("Hello from Child")end-- 创建对象并调用方法local obj = Child:new()obj:hello() -- 输出 "Hello from Child"在上面的示例中,我们定义了一个父类Parent,它有一个构造函数new和一个方法hello。
子类Child通过调用Parent:new()来继承父类的属性和方法,并覆盖了父类的hello方法。
析构函数析构函数是在对象销毁时自动调用的函数,它用于执行一些清理工作,例如释放资源、关闭文件等。
在Lua中,我们可以使用元表的__gc元方法来实现析构函数。
下面是一个示例,演示了如何在Lua中实现析构函数:-- 类local MyClass = {}function MyClass:new()local obj = {}setmetatable(obj, self)self.__index = selfreturn objendfunction MyClass:hello()print("Hello from MyClass")endfunction MyClass:__gc()print("Destructor called")-- 执行一些清理工作end-- 创建对象并调用方法local obj = MyClass:new()obj:hello() -- 输出 "Hello from MyClass"-- 销毁对象obj = nilcollectgarbage() -- 强制进行垃圾回收在上面的示例中,我们定义了一个类MyClass,它有一个构造函数new和一个方法hello。
Lua中类的实现原理探讨(Lua中实现类的方法)
Lua中类的实现原理探讨(Lua中实现类的⽅法)Lua中没有类的概念,但我们可以利⽤Lua本⾝的语⾔特性来实现类。
下⽂将详细的解释在Lua中实现类的原理,涉及到的细节点将拆分出来讲,相信对Lua中实现类的理解有困难的同学将会释疑。
类是什么?想要实现类,就要知道类到底是什么。
在我看来,类,就是⼀个⾃⼰定义的变量类型。
它约定了⼀些它的属性和⽅法,是属性和⽅法的⼀个集合。
所有的⽅法都需要⼀个名字,即使是匿名函数实际上也有个名字。
这就形成了⽅法名和⽅法函数的键值映射关系,即⽅法名为键,映射的值为⽅法函数。
⽐如说有⼀个类是⼈,⼈有⼀个说话的⽅法,那就相当于,⼈(Person)是⼀个类,说话(talk)是它的⼀个⽅法名,说话函数是它的实际说话所执⾏到的内容。
⼈也有⼀个属性,⽐如性别,性别就是⼀个键(sex),性别的实际值就是这个键所对应的内容。
理解了类实际上是⼀个键值对的集合,我们不难想到⽤Lua中⾃带的表来实现类。
实例是什么?如果理解了类实际就是⼀个键值映射的表,那么我们再来理解实例是什么。
实例就是具有类的属性和⽅法的集合,也是⼀个表了。
听起来好像和类差不多?类全局只有⼀个集合,相当于上帝,全局只有⼀块内存;⽽实例就普通了,普天之下有那么多⼈,你可以叫A说⼀句话,A便执⾏了他的说话⽅法,但是不会影响B的说话。
因为他们是实例,彼此分配着不同的内存。
说了那么多废话,其实实例就是由类创建出来的值,试着把类想象成类型⽽不是类。
两个语法糖试着创建⼀个⼈类 Person复制代码代码如下:Person = {name="这个⼈很懒"}以上代码将Person初始化为⼀个表,这个表拥有⼀个为name的键,其默认值是"这个⼈很懒"。
说成⽩话就是⼈类拥有⼀个叫名字的属性。
那就再赋予⼈类⼀个说话的功能吧。
复制代码代码如下:Person.talk = function(self, words)print(.."说:"..words)end以上代码在Person表中加⼊⼀个键值对,键为talk,值为⼀个函数。
详解Lua中的元表概念
详解Lua中的元表概念元表是⼀个表,有助于改变它连接到⼀个密钥集和相关的元⽅法的帮助下表的⾏为。
这些元⽅法是强⼤的lua功能,如:更改/添加功能,以运算符表查看metatables当钥匙不在使⽤__index元表中的表可⽤。
有迹象表明,在处理metatables其中包括使⽤了两种重要的⽅法,setmetatable(table,metatable): 这个⽅法是⽤来设置元表的⼀个表。
getmetatable(table): 此⽅法⽤于获取表的元表。
让我们先来看看如何设置⼀个表作为另⼀个元表。
它如下所⽰。
复制代码代码如下:mytable = {}mymetatable = {}setmetatable(mytable,mymetatable)上⾯的代码可以在⼀个单⼀的⾏被表⽰为如下所⽰。
复制代码代码如下:mytable = setmetatable({},{})__index元表的查找元表时,它不是在表中提供⼀个简单的例⼦如下所⽰。
复制代码代码如下:mytable = setmetatable({key1 = "value1"}, {__index = function(mytable, key)if key == "key2" thenreturn "metatablevalue"elsereturn mytable[key]endend})print(mytable.key1,mytable.key2)当我们运⾏上⾯的程序,会得到下⾯的输出。
复制代码代码如下:value1 metatablevalue让解释发⽣了什么事,在上⾯的例⼦中的步骤,该表mytable 这⾥ {key1 = "value1"}.元表设置为mytable中包含⼀个函数 __index 我们称之为元⽅法。
元⽅法确实仰视的索引“key2”⼀个简单的⼯作,如果找到,则返回“metatablevalue”,否则返回相应mytable索引的值。
Lua类和类继承实现
Lua类和类继承实现Lua本⾝是不能像C++那样直接实现继承,但我们可以⽤万能的table表来实现。
以下我总结了三种⽅式的类以及继承的实现第⼀、官⽅的做法,使⽤元表实现原理参照《Programming in lua》 Object.lua Object = {class_id = 0}function Object:new(o)o = o or {}setmetatable(o,self) -- 对象o调⽤不存在的成员时都会去self中查找,⽽这⾥的self指的就是Objectself.__index = selfreturn oend---以下我们创建对象来测试以下local o1 = Object:new()o1.class_id = 11;local o2 = Object:new()o2.class_id = 22;以上我们就利⽤元表实现了⼀个类,但这个类没有任何⾏为,以下我们继承上⾯的类DisplayObject.luaDisplayObject = Object:new()-- 现在为⽌,DisplayObject只是Object的⼀个实例,注意以下代码D = DisplayObject:new(width = 100,height = 50)-- DisplayObject从Object继承了new⽅法,当new执⾏的时候,self参数指向DisplayObject。
所以,D的metatable是DisplayObject,__index 也是DisplayObject。
这样,D继承了DisplayObject,后者继承了Object。
---在Lua中⾯向对象有趣的⼀个⽅⾯是你不需要创建⼀个新类去指定⼀个新的⾏为。
第⼆、复制表⽅式我们同样使⽤上⾯的Object,换种写法--Lua中的⾯向对象--[[复制表⽅式⾯向对象参数为⼀张表,通过遍历这张表取值,赋给⼀张空表,最后返回新建的表,来达到克隆表]]function cloneTab(tab)local ins = {}for key, var in pairs(tab) doins[key] = varendreturn insendObject = {class_id = 1}function Object.new() local o = cloneTab(Object) return oend-- 使⽤这个类local p = Object.new()继承实现DisplayObject.lua--[[复制表第⼀参数是⽬标表,第⼆个参数是需要复制的表通过遍历tab来取值将它赋值到⽬标表中]]function copy(dist,tab)for key, var in pairs(tab) dodist[key] = varendendDisplayObject = {}function DisplayObject.new()local ss = Object.new()copy(ss,DisplayObject)return ssendlocal p1 = DisplayObject.new()第三,使⽤函数闭包的形式实现⾯向对象--以函数闭包的形式实现⾯向对象--定义⼀个⽅法,函数闭包实现⼀个类的概念function People(name)local self = {}--初始化⽅法,私有的local function init() = nameendself.sayHi = function ()print("Hello ")end--调⽤初始化init()return selfend--实例化⼀个对象local p = People("ZhangSan")p:sayHi()--函数闭包的形式实现类继承function Man(name)local self = People(name)-- local function init()---- endself.sayHello = function ()print("Hi ")endreturn selfendlocal m = Man("Lisi")--m:sayHello()m:sayHi()PS;关于继承类,cocos2d-x v3版本提供⼀个更好更便捷的⽅式来实现。
Lua-面向对象中类的构造
Lua-⾯向对象中类的构造在Lua中,我们可以通过table+function来模拟实现类。
⽽要模拟出类,元表(metatable)和__index元⽅法是必不可少的。
为⼀个表设置元表的⽅法:table = {}metatable = {}setmetatable(table, metatable)或者table = setmetatable({},{})下⾯看⼀个简单的例⼦:local t = {k1 = "aaa"}local mt = {k2 = "bbb",__index = {k3 = "ccc"}}setmetatable(t, mt)print("k1:", t.k1, "k2:", t.k2, "k3:", t.k3)输出:k1: aaa k2: nil k3: ccc从例⼦可以看出,查找表元素时会从表的元表的__index键中查找。
查找⼀个表元素的规则如下:1.在表中查找,如果找到,返回该元素;如果找不到,继续22.判断该表是否有元表,如果没有,返回nil;如果有,继续33.判断元表中是否有__index⽅法,如果__index⽅法为nil,返回nil;如果__index⽅法是⼀个表,则重复 1,2,3;如果__index⽅法是⼀个函数,则返回该函数的返回值。
除了有__index元⽅法外,还有__newindex,__add,__sub等很多原⽅法,可查看Lua⽂档在了解了元表和元⽅法后,我们就可以模拟类的实现了。
local A = {a1 = "this is a1",a2 = 100}function A.new()local o = {}setmetatable(o, A)A.__index = Areturn oendfunction A:Print()print("This is A:Print ")endlocal a = A.new()a:Print()输出结果:This is A:Print以上就是⼀个类的简单实现⽅式,当然,我们也可以把它的实现封装到⼀个function中,这样会更⽅便我们类的创建和使⽤。
Lua五:类与继承的实现
Lua五:类与继承的实现Lua中没有类,即没有在对象⽣成中有模⼦的概念,但是有原型的概念。
基于原型的语⾔(prototype-based language)中,每个对象可以有⼀个原型(prototype)。
原型也是⼀种普通的对象,当对象(类的实例)遇到⼀个未知操作时会⾸先在原型中查找。
类和原型都是⼀种组织多个对象间共享⾏为的⽅式。
创建原型的⽅法如setmetatable(A, {__index = B}),即把B作为A的原型。
下⾯的代码是简单表达账户存取和提取的操作:Account = { balance=0}function Account : withdraw ( v)self.balance = self.balance – vendfunction Account : deposit (v)self.balance = self.balance + vend现在,需要实现类的概念,即Account作为类,下列代码中定义的a作为其对象。
local mt = {__index = Account}function Account. new (o) --该函数⽤于新建账户,即创建对象o = o or {f} --如果⽤户没有提供则创建⼀个新的表setmetatable(o,mt ) --将mt作为新创建的对象的元表,⽽元表中的__index为Account类return oenda = Account . new{ balance = 0}a : deposit ( 100.00 ) --相当于 getmetatable(a).__index . deposit(a,100.00)对于上述代码,我们可以进⾏⼀些改进。
⽅法new会变成:function Account : new ( o)o = o or {}self. __index = selfsetmetatable(o, self)return oend该改进是,不创建扮演元表⾓⾊的新表⽽是把表Account直接⽤作元表。
Lua:元表(metatable)与元方法(meatmethod)
Lua:元表(metatable)与元⽅法(meatmethod)元表概念:引⾔:Lua中的每个值都有⼀套预定义的操作集合,如数字相加等。
但⽆法将两个table相加,此时可通过元表修改⼀个值的⾏为,使其在⾯对⼀个⾮预定义的操作时执⾏⼀个指定操作。
访问机制:⼀般的元⽅法都只针对Lua的核⼼,也就是⼀个虚拟机。
它会检测⼀个操作中的值是否有元表,这些元表是否定义了关于次操作的元⽅法。
例如两个table相加,先检查两者之⼀是否有元表,之后检查是否有⼀个叫“__add”的字段,若找到,则调⽤对应的值。
“__add”等即时字段,其对应的值(往往是⼀个函数或是table)就是“元⽅法”。
元表实例setmetatable(只能⽤于table)和getmetatable(⽤于任何对象)语法:setmetatable (table, metatable),对指定table设置metatable 【如果元表(metatable)中存在__metatable键值,setmetatable会失败】语法:tmeta = getmetatable (tab),返回对象的元表(metatable) 【如果元表(metatable)中存在__metatable键值,当返回__metatable的值】代码:print(getmetatable("lua")) -->table: 002F19B8print(getmetatable(10)) -->nil--使⽤__metatable可以保护元表,禁⽌⽤户访问元表中的成员或者修改元表。
tA = {}mt = {}getmetatable(tA, mt)mt.__metatable = "lock"setmetatable(tA, mt)print(getmetatable(tA)) -->lock算术类元⽅法: 字段:__add __mul __ sub __div __unm __mod __pow (__concat)代码:(两个table相加)tA = {1, 3}tB = {5, 7}--tSum = tA + tBmt = {}mt.__add = function(t1, t2)for _, item in ipairs(t2) dotable.insert(t1, item)endreturn t1endsetmetatable(tA, mt)tSum = tA + tBfor k, v in pairs(tSum) doprint(v)end关系类元⽅法:字段:__eq __lt(<) __le(<=),其他Lua⾃动转换 a~=b --> not(a == b) a > b --> b < a a >= b --> b <= a 【注意NaN的情况】代码:--⽐较集合⼤⼩ <mt = {}function mt.__lt(tA, tB)return #tA < #tBendtA, tB = {3}, {1, 2}setmetatable(tA, mt)setmetatable(tB, mt)print(tA < tB)table访问的元⽅法:字段: __index __newindex__index:查询:访问表中不存的字段rawget(t, i)__newindex:更新:向表中不存在索引赋值rawswt(t, k, v)贯穿《Programming in Lua》元表与元⽅法整张的实例--[[Set = {}mt = {} --元表function Set.new(l)local set = {}setmetatable(set, mt)for _, v in ipairs(l) doset[v] = trueendreturn setend--================================================function Set.tostring(set)local l = {}for e in pairs(set) dol[#l + 1] = eendreturn "{" .. table.concat(l, ",") .. "}"endfunction Set.print(s)print(Set.tostring(s))end--1 加(__add), 并集===============================function Set.union(a, b)--[[ if getmetatable(a) ~= mt or getmetatable(b) ~= mt thenerror("attemp to 'add' a set with a non-set value", 2) --error第⼆个参数的含义P116 end]]local res = Set.new{}for k in pairs(a) do res[k] = true endfor k in pairs(b) do res[k] = true endreturn resends1 = Set.new{10, 20, 30, 50}s2 = Set.new{30, 1}--print(getmetatable(s1))--print(getmetatable(s2))mt.__add = Set.unions3 = s1 + s2--Set.print(s3)--[[元表混⽤s = Set.new{1, 2, 3}s = s + 8Set.print(s + 8)]]--2 乘(__mul), 交集==============================function Set.intersection(a, b)local res = Set.new{}for k in pairs(a) dores[k] = b[k]endreturn resendmt.__mul = Set.intersection--Set.print(s2 * s1)--3 关系类===================================NaN的概念====mt.__le = function(a, b)for k in pairs(a) doif not b[k] then return false endendreturn trueendmt.__lt = function(a, b)return a <= b and not (b <= a)endmt.__eq = function(a, b) --竟然能这么⽤!?----return a <= b and b <= aendg1 = Set.new{2, 4, 3}g2 = Set.new{4, 10, 2}print(g1 <= g2)print(g1 < g2)print(g1 >= g2)print(g1 > g2)print(g1 == g1 * g2)--]]--============================================--4 table访问的元⽅法=========================--[[--__index有关继承的典型⽰例Window = {}Window.prototype = {x = 0, y = 0, width = 100, height} Window.mt = {}function Window.new(o)setmetatable(o, Window.mt)return oendWindow.mt.__index = function (table, key)return Window.prototype[key]endw = Window.new{x = 10, y = 20}print(w.width)--__index修改table默认值function setDefault (t, d)local mt = {__index = function () return d end}setmetatable(t, mt)endtab = {x = 10, y = 20}print(tab.x, tab.z)setDefault(tab, 0)print(tab.x, tab.z)--]]--13.4.5 只读的tablefunction readOnly(t)local proxy = {}local mt = {__index = t,__newindex = function(t, k, v)error("attempt to update a read-only table", 2)end}setmetatable(proxy, mt)return proxyenddays = readOnly{"Sunday", "Monday", "Tuesday", "W", "T", "F", "S"} print(days[1])days[2] = "Noday"。
lua__init元方法
lua__init元方法(实用版3篇)《lua__init元方法》篇1Lua的`__init`元方法是一个特殊的方法,它可以在类被实例化时自动调用。
这个方法通常用于初始化类的属性或方法。
在Lua中,可以通过在类定义中定义`__init`方法来实现`__init`元方法。
下面是一个示例:```lua--定义一个类local MyClass = {}--定义一个__init方法MyClass.__init = function(self, name) = nameend--定义一个__new方法,用于创建对象实例MyClass.__index = MyClassMyClass.__new = function(self, name)local obj = {}setmetatable(obj, self)self.__init(obj, name)return objend--测试类实例化local myInstance = MyClass("John")print() --输出:John```在上面的示例中,我们定义了一个名为`MyClass`的类,并定义了一个`__init`元方法来初始化类的属性`name`。
然后,我们定义了一个`__new`方法,用于创建对象实例。
在`__new`方法中,我们使用`setmetatable`函数将新创建的对象实例与类关联起来,并调用`__init`方法来初始化对象的属性。
《lua__init元方法》篇2在Lua中,可以通过实现`__init`元方法来为全局变量添加初始化功能。
元方法是一个可以接收多个参数的函数,可以在调用时接受全局变量作为参数。
以下是一个示例:```luafunction __init(global_var)--初始化全局变量的代码print("Initializing global variable:", global_var)end```在上面的示例中,`__init`元方法接受一个全局变量作为参数,并在控制台输出一条消息。