Lua--table、模块、元表与元方法、面向对象
table
数组
table 可以定义一维、二维、多维数组。但是数组的索引从1开始,无需声明数组长度。
cities={"北京","上海","广州"}
cities[4]="南京"
同一数组的元素可以是任意类型。
map
table可以定义出类似map的key-value数据结构。
访问时可通过key访问,也可以指定索引来访问。
emp={name="张三",age=22,dept="IT"}
emp["gender"]="男"
print(emp["name"])
emp.addr="北京"
print(emp.age)
-- 也可以使用表达式作为key ,表达式需要中括号括起来。
arr= {
["emp_".."xxx"] = true,
[2+3] = "hello",
["hi"] = 123
}
print(arr.emp_xxx) -- true
print(arr[5]) -- hello
print(arr.hi) -- 123
混合结构
将数组和key-value 混合在一个table中, key-value不会占用数组的数字索引值。
emp={"北京",name="张三","上海",age=22,"广州",dept="IT"}
print(1) -- 北京
print(2) -- 上海
print(3) -- 广州
table操作函数
-
table.concat() 字符串连接
table.concat(table[,sep[,start[,end]]]) emp={"北京",name="张三","上海",age=22,"广州",dept="IT"} table.concat(emp,",",1,2) -- "北京,上海"将指定的table 数组元素 进行字符串连接。
连接从start索引位置到end索引位置的所有数组元素,元素间使用sep隔开。
如果table是一个混合结构,那么这个连接与key-value无关,仅是连接数组元素。
-
table.unpack() 拆包
返回指定table的数组中从第i个元素到第j个元素的值。i和j可选,默认i=1,j=最后一个元素。
emp={"北京","上海","广州","深圳","大连"} print(table.unpack(emp,2,3)) -- 上海 广州 -
table.pack() 打包
此函数是一个可变参。将指定参数打包成一个table返回。
返回的table中有一个属性n,表示table包含元素的个数。
t=table.pack("北京","上海","广州","深圳","大连") print(t.n) -- 5 -
table.maxn() 返回table中的数组的最大索引,即数组包含元素的个数。
-
table.insert() 指定table的数组部署指定位置插入一个元素,其后面的元素会后移。不指定位置,就插入到数组部分末尾。
t=table.pack("北京","上海","广州","深圳","大连") table.insert(t,2,"郑州") table.insert(t,"成都") -
table.remove() 删除并返回table数组部分指定位置的元素。其后面的元素会前移。不指定位置,默认删除数组中的最后一个元素。
table.remove(t,3) -
table.sort() 指定table的数组元素升序排序,也可以按照指定函数的规则进行排序。
注意:
- 如果arr中既有字符串,又有数值型,那么排序会报错。
- 如果数组中多个元素相同,那么相同的元素排序结果不确定。
- 如果数组元素中包含nil,那么排序会报错。
迭代器
Lua有两个迭代器pairs(table)与ipairs(table),用于泛型for循环
- pairs(table):迭代整个table元素,无论是数组元素,还是key-value
- ipairs(table):只迭代table中的数组元素。
emp={"北京",name="张三","上海",age=22,"广州",dept="IT"} for i,v in ipairs(emp) do print(i,v) end -- 输出结果如下: 1 北京 2 上海 3 广州 for i,v in pairs(emp) do print(i,v) end -- 输出结果如下: 1 北京 2 上海 3 广州 name 张三 age 22 dept IT模块
Lua可以把一些公用的代码放在一个文件,以API接口的形式在其他地方调用,有利于代码复用和降低代码耦合度。
模块文件主要由table组成。在table中添加相应的变量、函数,最后文件返回该table即可。
如果其他文件中需要使用该模块,通过require导入该模块即可。
定义模块
-- 定义一个模块 rectangle = {} -- 为模块添加一个变量 rectangle.pi = 3.14 -- 为模块添加函数 function rectangle.perimeter(a,b) return (a+b)*2 end -- 以匿名函数的方式为模块添加一个函数 rectangle.area= function (a,b) return a*b end -- 定义一个全局变量(与模块无关) goldenRatio = 0.618 -- 定义一个局部函数(与模块无关) local function circulaArea(r) return rectangle.pi*r*r end -- 定义一个全局函数(与模块无关) function maxCirculArea(a,b) local r =math.min(a,b) return circulaArea(r) end return rectangle将以上文件保存为rectangle.lua
使用模块
require ("文件路径")或者 require “文件路径”,可以省略括号。
其中文件名不能写.lua扩展名。
require()函数有返回值,返回的是模块文件最后return的table。可以使用一个变量接收这个table作为模块的别名,后面就可以使用别名来访问模块了。
-- 导入模块 rect = require "rectangle" -- 访问模块属性 print(rectangle.pi) print(rect.pi) -- 访问与模块无关内容 print(goldenRatio) print(maxCirculArea(3,5))再看模块
模块文件中还可以定义其他与table无关的内容。这些全局变量与函数就是普通的全局变量与函数,与模块无关,其会随着模块的导入而同时导入。
所以在使用时可以直接使用,无需也不能添加模块名称。
元表与元方法
元表:普通table的元数据表
元方法:元表中定义的普通表的默认行为。
·每个普通table都可为其定义一个元表,用于扩展其行为。
比如:对于table与数值相加的行为,Lua没有定义,用户可通过为其指定元表来扩展。
或者当用户访问不存在的table元素,Lua默认返回nil,此时可以给table指定元表来扩展该行为,给用户提示,并返回指定的值。
重要函数
-
setmetatable(table,metatable):将metatable指定为普通表table的元表。
-
getmetatable(table):获取普通表的元表。
__index元方法
当用户对table进行访问,访问的数组索引或者key不存在,系统就会自动调用元表的__index元方法。该重写的方法可以是一个函数,也可以是另一个表。如果重写的
__index元方法是函数,且有返回值,则直接返回;如果没有返回值,则返回nil。emp={"北京",name="张三","上海",age=22,"广州",dept="IT"} -- 声明一个元表 meta = {} -- 将table与元表相关联 setmetatable(emp,meta) -- 有返回值的情况 meta.__index = function (tab,key) return "访问"..key.."的值不存在" end -- 或者无返回值的情况 meta.__index = function (tab,key) print("访问"..key.."的值不存在") end print(emp.x) print(emp[2]])__index 元方法是另一个table的情况
emp={"北京",name="张三","上海",age=22,"广州",dept="IT"} -- 声明一个元表 meta = {} -- 将table与元表相关联 setmetatable(emp,meta) -- 再定义一个普通表 other= {} other[5] = "成都" other[6] = "重庆" -- 指定元表为另一个普通表 meta.__index = other -- 在原始表中找不带,会到元表指定的普通表中查找 print(emp[6]) -- 重庆__newindex元方法
当为table中一个不存在的索引或key赋值时,会自动调用元表的__newindex元方法。
重写该方法可以是一个函数,也可以是另一个表。
如果重写__newindex元方法是函数,且有返回值,则直接返回;无返回值,就返回nil。
emp={"北京",name="张三","上海",age=22,"广州",dept="IT"} -- 声明一个元表 meta = {} -- 将原始表与元表关联 setmetatable(emp,meta) -- 无返回值情况 function meta.__newindex(tab,key,value) print("新增的key="..key..",value="..value) -- 将新增的key-value加入到原始表 rawset(tab,key,value) end emp.x = "青岛" print(emp.x)emp={"北京",name="张三","上海",age=22,"广州",dept="IT"} -- 声明一个元表 meta = {} -- 将原始表与元表关联 setmetatable(emp,meta) -- 定义一个普通表 other = {} meta.__newindex = other emp.x = "大连" print(emp.x) -- nil print(other.x) -- 大连运算符元方法
如果要为一个表扩展+、-、>、==等运算功能,可重写对应的元方法。
比如:要扩展+运算功能,可重写__add元方法。这样当一个table在进行加法运算时,就会自动调用其元表的
__add元方法emp={"北京",name="张三","上海",age=22,"广州",dept="IT",32 ,11} -- 声明一个元表 meta = { __add = function (tab,num) for k,v in pairs(tab) do if type(v) == "number" then -- 若value是数值类型,就做加法 tab[k] =v+num end end -- 返回变化过的table return tab end } -- 将原始表与元表关联 setmetatable(emp,meta) empsum = emp + 5其他的运算符元方法还有 减法、乘法等,可以在Lua官网查询

__tostring元方法
直接输出一个table,输出的是table的内存地址,如果要输出其内容,可重写__tostring元方法
emp={"北京",name="张三","上海",age=22,"广州",dept="IT",32 ,11}
-- 声明一个元表
meta = {
__add = function (tab,num)
for k,v in pairs(tab) do
if type(v) == "number" then
-- 若value是数值类型,就做加法
tab[k] =v+num
end
end
-- 返回变化过的table
return tab
end,
__tostring = function (tab)
str = ""
for k,v in pairs(tab) do
str = str.." "..k..":"..v
end
return str
end
}
-- 将原始表与元表关联
setmetatable(emp,meta)
print(emp)
__call元方法
当把一个table以函数形式来使用时,会调用重写的__call元方法。
该用法可以简化对table的操作,将对table的操作与函数直接结合。
emp={"北京",name="张三","上海",age=22,"广州",dept="IT",32 ,11}
-- 声明一个元表
meta = {
__add = function (tab,num)
for k,v in pairs(tab) do
if type(v) == "number" then
-- 若value是数值类型,就做加法
tab[k] =v+num
end
end
-- 返回变化过的table
return tab
end,
__tostring = function (tab)
str = ""
for k,v in pairs(tab) do
str = str.." "..k..":"..v
end
return str
end,
__call = function (tab,num,str)
for k,v in pairs(tab) do
if type(v) == "number" then
tab[k] = v+num
elseif type(v) == "string" then
tab[k] = v..str
end
end
return tab
end
}
-- 将原始表与元表关联
setmetatable(emp,meta)
newemp = emp(3,"-haha")
for k,v in pairs (newemp) do
print(k..":"..v)
end
元表单独定义
可以将元素单独定义为一个文件。文件中仅可定义一个元表,且一般文件名与元表名称相同。
若一个文件要使用其他文件中定义的元表,需要使用require "元表文件名" 即可。
如果想扩展该元表而不想修改元表文件,可以在用户自己文件中重写其对应功能的元方法即可。
-- 声明一个元表
meta = {
__add = function (tab,num)
for k,v in pairs(tab) do
if type(v) == "number" then
-- 若value是数值类型,就做加法
tab[k] =v+num
end
end
-- 返回变化过的table
return tab
end,
__tostring = function (tab)
str = ""
for k,v in pairs(tab) do
str = str.." "..k..":"..v
end
return str
end,
__call = function (tab,num,str)
for k,v in pairs(tab) do
if type(v) == "number" then
tab[k] = v+num
elseif type(v) == "string" then
tab[k] = v..str
end
end
return tab
end
}
将以上内容保存为meta.lua,需要使用的时候直接引入但后关联就可。
-- 导入元表
require "meta"
emp={"北京",name="张三","上海",age=22,"广州",dept="IT",32 ,11}
-- 将原始表与元表关联
setmetatable(emp,meta)
-- 重写__index元方法
meta.__index = function(tab,key)
print("访问的"..key.."不存咋")
end
newemp = emp(3,"-haha")
for k,v in pairs (newemp) do
print(k..":"..v)
end
面向对象
Lua没有类的概念,但通过table、function、元表 可以模拟和构造出类这样的功能结构。
简单对象的创建
通过table与function 可以创建一个简单的Lua对象:table为Lua对象赋予属性,function 为Lua 对象赋予行为。
-- 创建一个名称为animal的对象
animal = {
name = "dog",
age = 3,
color = "black",
bark = function ()
print("woof!")
end
}
animal.bark()
类的创建
通过table、function与元表可以定义类:
使用一个table作为基础类
使用一个function 作为此基础类的new()方法
在new()方法中创建一个空表,再为该空表指定一个元表。
此元表重写__index 元方法,且将基础表指定为重写的__index元方法。
由于new()中的表是空表,所以访问的所有key都会从基础表中查找。
-- 创建一个名称为animal的类
Animal = {
name = "no_name",
age = 0
}
function Animal:bark(voice)
print(self.name.."叫了一声"..voice)
end
-- 创建一个无参构造器
function Animal:new()
-- 创建一个空表 来存储对象
local obj = {}
-- 为新表设置元表为AnimalL
-- 在新表中找不到key时,就会去AnimalL中找到key
setmetatable(obj,self)
self.__index = self
return obj
end
-- 添加一个含参数的构造器
function Animal:new(name,age,type)
local obj = {}
setmetatable(obj,self)
self.__index = self
obj.name = name
obj.age = age
obj.type = type
return obj
end
animal = Animal:new()
-- 给对象赋值,下面的name、age、type 实际上都加到了新表中,而不是AnimalL中
animal.name = "旺财"
animal.age = 3
animal.type = "狗"
print(animal.name.."的年龄是"..animal.age.."岁了,它是一只"..animal.type)
animal:bark("汪汪")
-- 调用带参数的构造器创建对象
animal2 = Animal:new("小花",2,"猫")
print(animal2.name.."的年龄是"..animal2.age.."岁了,它是一只"..animal2.type)
animal2:bark("喵喵")
-- 为Animal创建一个子类
Cat = Animal:new()
Cat.type="猫"
Cat.eyes = "绿眼睛"
function Cat:catchMouse()
print(self.name.."抓住了一只老鼠")
end
tomcat = Cat:new("汤姆",5)
print(tomcat.name.."的年龄是"..tomcat.age.."岁了,它是一只"..tomcat.type..",有"..tomcat.eyes)
tomcat:catchMouse()
执行结果如下:

本文来自博客园,作者:NE_STOP,转载请注明原文链接:https://www.cnblogs.com/alineverstop/p/20025197
浙公网安备 33010602011771号