目录
介绍
lua的魔法方法是什么呢?这里可以参考py的魔法方法 他实际是为了模拟面向对象编程而出现的概念
魔法方法都是以__两个下划线开头的 这点与py中相同
魔法方法的定义方式与对象类似 而我之前的一篇文章说了 lua的对象就是一个table
但是这里不能直接写在表中 这样lua会认为这是一个普通的方法 而不是魔法方法
魔法方法又叫元方法 lua基础好的朋友就知道了 lua中有一个函数 这个函数的作用是设置元表
而这个方法就是setmetatable这个方法需要两个参数 第一个参数为需要设置的元方法(魔法方法)的对象(表)第二个参数就是包含了元方法(魔法方法)的对象(表)
0.setmetatable
例子
local enumClass = {}
local classFunction = {
__call = function(self)
return self
end
}
setmetatable(enumClass,ClassFunction)
0.1.__add
__add:这个魔法方法用于定义相加操作符(+)的行为。例如,当对两个表进行相加时,Lua 将调用该方法来执行实际的相加操作。
__add(table1, table2):相加操作的参数包括两个表,即被加数和加数。
在lua中 对象是可以被相加(+)的 只是在相加之前 需要手动添加__add元方法 相信写gglua的朋友应该是没有这样写过 但其实是可以的
例如
class={
value=0
}
metaObjects={
__add=function(table1,table2)-- table1=被加数 table2=加数
for i, v in pairs(table2) do
table1.value=table1.value+v
end
return table1.value
end
}
setmetatable(class,metaObjects)
demoClass={
value=2,
age=18
}
print(class+demoClass)-- 20
print(class.value)-- 20
0.2.__sub
__sub:这个魔法方法用于定义相减操作符(-)的行为。类似地,当对两个表进行相减时,Lua 将调用该方法来执行实际的相减操作。
__sub(table1, table2):相减操作的参数包括两个表,即被减数和减数。
例如
class={
value=0
}
metaObjects={
__add=function(table1,table2)
for i, v in pairs(table2) do
table1.value=table1.value+v
end
return table1.value
end,
__sub=function(table1,table2)
for i, v in pairs(table2) do
table1.value=table1.value-v
end
return table1.value
end
}
setmetatable(class,metaObjects)
demoClass={
value=2,
age=18
}
print(class-demoClass)-- -20
print(class.value)-- -20
0.3.总结
这里还有很多类似的元方法 就不一一举例了 大家可以自己手动写一个测试
-
__mul:这个魔法方法用于定义相乘操作符(*)的行为。当对两个表进行相乘时,Lua 将调用该方法来执行实际的相乘操作。
-
__div:这个魔法方法用于定义相除操作符(/)的行为。当对两个表进行相除时,Lua 将调用该方法来执行实际的相除操作。
-
__mod:这个魔法方法用于定义取模操作符(%)的行为。当对两个表进行取模运算时,Lua 将调用该方法来执行实际的取模操作。
-
__pow:这个魔法方法用于定义乘方操作符(^)的行为。当对两个表进行乘方运算时,Lua 将调用该方法来执行实际的乘方操作。
-
__unm:这个魔法方法用于定义一元负号操作符(-)的行为。当对一个表应用一元负号时,Lua 将调用该方法来执行实际的负号操作。
-
__concat:这个魔法方法用于定义字符串连接操作符(..)的行为。当对两个表进行字符串连接时,Lua 将调用该方法来执行实际的连接操作。
-
__len:这个魔法方法用于定义 # 操作符的行为,它返回表的长度。当对一个表应用 # 操作符时,Lua 将调用该方法来获取表的长度。
-
__eq:这个魔法方法用于定义相等操作符(==)的行为。当对两个表进行相等比较时,Lua 将调用该方法来判断它们是否相等。
-
__lt:这个魔法方法用于定义小于操作符(<)的行为。当对两个表进行小于比较时,Lua 将调用该方法来判断它们的大小关系。
-
__le:这个魔法方法用于定义小于等于操作符(<=)的行为。当对两个表进行小于等于比较时,Lua 将调用该方法来判断它们的大小关系。
- __mul(table1, table2):相乘操作的参数包括两个表,即被乘数和乘数。
- __div(table1, table2):相除操作的参数包括两个表,即被除数和除数。
- __mod(table1, table2):取模操作的参数包括两个表,即被取模数和取模数。
- __pow(table1, table2):乘方操作的参数包括两个表,即底数和指数。
- __unm(table):一元负号操作的参数为一个表,即被取负数的表。
- __concat(table1, table2):字符串连接操作的参数包括两个表,即左字符串和右字符串。
- __len(table):返回表的长度,参数为一个表。
- __eq(table1, table2):相等比较操作的参数包括两个表,即被比较的两个表。
- __lt(table1, table2):小于比较操作的参数包括两个表,即被比较的两个表。
- __le(table1, table2):小于等于比较操作的参数包括两个表,即被比较的两个表。
1.常用的元方法
-
__index:这个魔法方法用于定义对表的索引操作的行为。当你试图访问一个表中不存在的键时,Lua 将调用该方法来返回对应的值。
-
__newindex:这个魔法方法用于定义对表的新索引操作的行为。当你试图给一个表中不存在的键赋值时,Lua 将调用该方法来执行实际的赋值操作。
-
__call:这个魔法方法用于定义对表的调用操作的行为。当你像调用函数一样调用一个表时,Lua 将调用该方法来执行实际的调用操作。
-
__tostring:这个魔法方法用于定义将表转换为字符串的行为。当你尝试将一个表转换为字符串时,Lua 将调用该方法来执行实际的转换操作。
1.1.__index
__index(table, key):对表的索引操作的参数包括一个表和一个键(key),表示要访问的表和索引值。
class={
value=0
}
metaObjects={
__index=function(table,key)
print(key.."被访问")
table[key]="白"
return table[key]
end
}
setmetatable(class,metaObjects)
print(class.value)-- -0
print(class.key)-- key被访问 白
1.2.__newindex
__newindex(table, key, value):对表的新索引操作的参数包括一个表、一个键(key)和一个值(value),表示要赋值的表、索引和值。
这个与__index的区别是newindex是在对不存在的键赋值时才会触发而index是只要访问就会触发
class={
value=0
}
metaObjects={
__newindex=function(table,key,value)
print(key.."被访问 尝试赋值"..value)
rawset(table,key,value.."白")
end
}
setmetatable(class,metaObjects)
class.key="作者:"
print(class.value)-- -0
print(class.key)-- 作者:白
需要重点注意 在newindex方法中给表中的字段赋值不能直接 table[key]=value 因为这样当你赋值时table表中还没有key这个字段 所以他还会调用newindex方法 这样就会无线递归 必须使用rawset函数进行赋值
1.3.__call
__call(table, ...):对表的调用操作的参数包括一个表和任意数量的参数,表示要调用的表和传递给表的参数。
这个魔法方法是我个人觉得最好用的(可能是Java写多了) 因为该方法可以实现Java的构造方法 用过的都知道多好用
但是lua实现起来肯定是要复杂一点了 但就算是这样 这也是lua对象的主要实现
但遗憾的是lua想实现每次创建对象都会在栈中开辟内存有点麻烦
直接调用是会调用的同一个内存
class={
name="",
age=0,
}
metaObjects={
__call=function(self,...)
args={...}
if #args==2 then
return self:create(...)
elseif #args == 0 then
return self:create2()
end
end
}
--- 构造方法
function class:create(name,age)
self.name=name
self.age=age
return self
end
--- 构造方法
function class:create2()
return self
end
setmetatable(class,metaObjects)
object=class("白",18)-- 创建对象
object2=class()-- 创建对象
print(class.name)-- 白
print(class.age)-- 18
print(object2.name)-- 白
print(object2.age)-- 18
1.4.__tostring
__tostring(table):将表转换为字符串的参数为一个表。
这个在电脑的lua环境 或者手机自己搭的lua环境中比较常用
在gg中用到的不是很多 因为gg默认其实是每个对象(表)都暗含了这个方法
这里注意 不确定是gg每个对象(表)都自动帮我们写了这个方法
因为gg的源码有点史 作者确实每看懂 也有可能是在别的方法实现的 不过都可以理解为gg自动帮我们写了这个魔法方法 作为学习的 其实也不需要深究他是怎么实现的
class={
name="",
age=0,
}
metaObjects={
__call=function(self,...)
args={...}
if #args==2 then
return self:create(...)
elseif #args == 0 then
return self:create2()
end
end,
__tostring=function(table)
local retString=""
for i, v in pairs(table) do
retString=retString..i.."="..tostring(v)..","
end
return retString
end
}
function class:create(name,age)
self.name=name
self.age=age
return self
end
function class:create2()
return self
end
setmetatable(class,metaObjects)
object=class("白",18)
print(class.name)-- 白
print(class.age)-- 18
print(object)-- age=18,create2=function: 00908100,create=function: 0090c7d8,name=白,