【3】Lua之使用表
【1】 用表来存储数据
(1) 创建和索引表
hello 和alice 指向同一个地址
、、、、、、、、、、、、、、、、、、、、
实际上,Lua允许使用除nil以外的任何值作为关键词
(2)从表中清除元素
对于给出的关键字,表中什么也没有存储。可以通过赋值 nil 的方法帮助我们从表中清除不再需要的条目
(3)字符串关键字的快捷方式
这种快捷的方式只有当关键词以字母或者下划线字符开头,并且只有字母、数字、下划线组成的时候才能执行。此外,关键词不能是Lua的保留关键字(如end)。
使用 [ ] 标记可以索引以数字开始的关键词
(4)创建有内容的表
如上:也可以通过字符串关键字的快捷方式
每一个例子的最后在结束之前都有一个逗号。
【2】把表当做数组使用
(1) 创建数组
数组是表的一种特殊情况。这部分所涉及的函数,只在处理从1开始的连续整数关键字时是可靠的。
(2)获取数组的长度
输出: 5
如下是一个空表![](https://i-blog.csdnimg.cn/blog_migrate/0db948abe464f12c84d115e9d700a63e.jpeg)
输出时0
如下程序:
![](https://i-blog.csdnimg.cn/blog_migrate/17851d32676f5d211697946db9c300fb.jpeg)
运行结果
![](https://i-blog.csdnimg.cn/blog_migrate/b406843ee9ed8b2ccfea536a43262698.jpeg)
(3)在数组中添加元素
Lua提供了一个标准的table.insert() 库函数,可以让添加数组元素变得更加简单。 table.insert()的语法是:
table.insert( foride , [ pos ,] value)
foride : 被修改的表
pos :添加元素所在的位置
value : 添加元素的值
结果:
在调用print_table 函数前 , 添加如下两行代码
(1-1)自动在列表的末尾添加新的元素
运行结果如下 ![](https://i-blog.csdnimg.cn/blog_migrate/42969dd69c75fa8c35d36ca685428d31.jpeg)
(1-2)在指定位置添加新的元素
运行结果如下:
![](https://i-blog.csdnimg.cn/blog_migrate/d3e38bcb5411a9531c6181e399335960.jpeg)
(1-3)
运行结果: ![](https://i-blog.csdnimg.cn/blog_migrate/843efab7d349fd99f751b5d68a10e737.jpeg)
(4)从数组中删除元素
Lua包含一个能从表中删除元素的函数
value =table.remove( foride , [ , pos] )
foride : 被修改的表
pos : 被移除元素所在的位置
value : 被删除的值
如下的程序: 移除了 foride 表中的最后一个 Nginx 和 第一个元素 Linux
![](https://i-blog.csdnimg.cn/blog_migrate/ab8689caf2a0a26a1faab39db4a43a8b.jpeg)
(5) 对数组中的元素排序
table.sort() 的语法遵循:
table.sort( foride [ , comp ] )
table.sort() 的第二个参数在下一篇介绍
![](https://i-blog.csdnimg.cn/blog_migrate/01660f30eb1b84119e6d43fc336d7952.jpeg)
上面的例子:因为表中的变量都是字符串,因此它们将会按字母顺序升序排列(默认)。如果包含的是数字,则排序方式相同。
如果遇到一些更加复杂的值(如表)。或者数组中的值是混合的(如字符串和数字),像这种简单的排序方式的效率就非常的低,table.sort() 的第二个参数允许你修改排序函数,因此它能够适应这种复杂的情况
【3】 用名称空间使用表
(1)创建 foride 名称空间
通过定义一个表,创建一个名称空间,以便存储函数
foride = { }
(2)向 foride 中添加函数
[1-1] 存储已有函数
![](https://i-blog.csdnimg.cn/blog_migrate/c14d0099d1c85a46b7cb01e6ad0e5fac.jpeg)
[1-2] 定义新函数
第一种形式通常是定义函数的最方便的方式。比起另一种,它的可读性更强。
![](https://i-blog.csdnimg.cn/blog_migrate/d5881222e694b803574219408f8432f2.jpeg)
【4】 表的面向对象编程
(1)创建非面向对象计数器
![](https://i-blog.csdnimg.cn/blog_migrate/003542b16a8530f3932d804a1c834778.jpeg)
(2)把表作为简单的对象
//=========================================================================
![](https://i-blog.csdnimg.cn/blog_migrate/e8ef007081e0096bf1856311d03212e8.jpeg)
//=========================================================================
在这个现实中,实际的计数器变量存储在一个表中(以对象形式)。与值交互的每一个函数都有一个名为self的参数,其被作为计数器对象。我们可以通过运行一下代码创建一个新的计数器。
![](https://i-blog.csdnimg.cn/blog_migrate/0a0cea16995e8d7b3d7770cb98c8ae72.jpeg)
因为这些函数只是Lua 值,并且他们是通过参数而不是一些神秘的隐藏变量进行工作的,所以你可以把他们复制到新的计数器中。事实上,即使把他们混合在一起,函数也能正常工作。
![](https://i-blog.csdnimg.cn/blog_migrate/99cbe7b96e7bb2ca6891939c89640399.jpeg)
(3)冒号调用对象方法
当调用一个对象的方法的时候,你可以使用冒号来代替句点,这个对象将会作为方法的第一个参数传递。意味着你可以调用foirde:get() 来代替 foride.get(foride) 。这个在后台自动运行的功能可以防止在每次调用方法时都要传递一次对象。
(4)用冒号定义函数
function tb1:MyModth() end 和 function tb1.MyModth(self) end 方法等价
![](https://i-blog.csdnimg.cn/blog_migrate/fb48220a7209cb3564ca28390eb98a31.jpeg)
(5)创建更佳的计数器
![](https://i-blog.csdnimg.cn/blog_migrate/13ba3c735861e9680b648703d52aab94.jpeg)
【‘5】利用元素对表进行扩展
在Lua中的每一个表都能够附带一个元表 (metatable)。 元表是一种二级表格。它提供了一些关于表应当该如何处理的附加信息。
(1)添加元表
元表是一个简单的表,它存储了和它有联系的的表的一些附加信息。他们能够被传递,能够被附加到很多表,并且随时可以更改。
为了重新定义表的行为,你必须创建一个元表,然后利用setmetatable() 函数将其附加到一个表对象。
这个函数有两个参数:
foride1 : 待改变的表
mt : 附加到foride1 的表
另外,setmetatable() 函数只返回一个参数,即作为第一个参数传入的表。当新建一个表来直接传递给 setmetatable() 时,这会相当有帮助。
运行下面的代码创建一些表,并且在每一个表上附加同样的元表(mt)。
可以使用getmetatable() 函数来验证元表是否已成功建立,这个函数将表作为第一个参数,返回一个元表。当没有元表时,它返回nil 。
![](https://i-blog.csdnimg.cn/blog_migrate/4da32d8cdfc017af973f2f99c5aae20f.jpeg)
![](https://i-blog.csdnimg.cn/blog_migrate/613350e77dba0d68ecda9eae9a675925.jpeg)
(2)定义元方法
元方法(metamethod)其实是一个函数,它存储在元表中,且带有一个给定的键。元方法有很多种,其参数各不相同,每一个元方法都以两个下划线开头。
常用的元方法
元方法 参数个数 描述
------------------------------------------------------------------------------------------------------------------------------------------------------------
_ _add 2 定义加法的行为
------------------------------------------------------------------------------------------------------------------------------------------------------------
_ _mul 2 定义乘法的行为
------------------------------------------------------------------------------------------------------------------------------------------------------------
_ _div 2 定义除法的行为
------------------------------------------------------------------------------------------------------------------------------------------------------------
_ _sub 2 定义减法的行为
------------------------------------------------------------------------------------------------------------------------------------------------------------
_ _unm 1 定义非的行为(一元减法)
------------------------------------------------------------------------------------------------------------------------------------------------------------
_ _tostring 1 定义当表是tostring() 的参数时的行为,它也会影响到
直接调用tostring() 的print()函数
------------------------------------------------------------------------------------------------------------------------------------------------------------
_ _concat 2 定义当使用连接操作时的行为
------------------------------------------------------------------------------------------------------------------------------------------------------------
_ _index 2 定义当表用该表不存在的键检索时的行为
------------------------------------------------------------------------------------------------------------------------------------------------------------
_ _newindex 3 定义当用表中未预先设置的键检索时的行为
------------------------------------------------------------------------------------------------------------------------------------------------------------
[1] 使用 _ _add, _ _sub, _ _mul 和 _ _div 定义基本运算
![](https://i-blog.csdnimg.cn/blog_migrate/45851ea3061e84ae41d7f4095edfbb7e.jpeg)
![](https://i-blog.csdnimg.cn/blog_migrate/b2d67d24aa00938505873ca45a0a8ffd.jpeg)
[2]使用 _ _unm 定义负运算
![](https://i-blog.csdnimg.cn/blog_migrate/eb4dcf50fc36b63c15d8907036758bf6.jpeg)
![](https://i-blog.csdnimg.cn/blog_migrate/50d4d7226cd7154eaa7b271713895276.jpeg)
[3]使用 _ _tostring 建立有意义的输出
![](https://i-blog.csdnimg.cn/blog_migrate/5a21aa0a9c745864389059ed032e6b3a.jpeg)
[4] 使用 _ _concat 连接表
对于表,连接运算了加法运算一样,所以你可以使用同样的函数来构造__concat 元方法。
两个方法都带有两个参数,一个返回值。另外,两者都是典型的连锁式运算,所以你要确保你的结果也能连接上。
![](https://i-blog.csdnimg.cn/blog_migrate/dd302b260ea3c7906d5b9583e7ca76b0.jpeg)
因为__tostring 元方法仍然处于激活状态,结果表被转化为串表达式,甚至显示也是如此
![](https://i-blog.csdnimg.cn/blog_migrate/c4a1f0e80a64a29f9037f396ba1f3e41.jpeg)
[5]使用 _ _index 在后备表中浏览
一般来说,当所要查找的键没有和表中的任意一个值相关联时,将返回nil。 然而,在一般情况下,其他的返回值会更有意义, __index 是允许这种情况出现的。以下就是当索引没有找到时所发生的。
(1)表使用一个没有相关值的键来进行索引
(2) 如果表的__index元表项是一个表,就返回那个表中键所对应的项(当不存在时,返回nil)
(3)如果表有__index元表项,就返回这个表调用函数的结果,以键值作为参数。
表的使用如下:
![](https://i-blog.csdnimg.cn/blog_migrate/51a0b14c1e2806f685c6afcb71c2cc5b.jpeg)
这个例子创建了一个表,包含着用于德国服务器的英语短语 “Night elf” 。 另外,有一个默认的表包含一些英语短语 ”Human“和 “Night elf”.。 当检索表deDE_races 时,如果没有找到答案,Lua 就顺便访问元表的 __index 项, 然后返回结果。
![](https://i-blog.csdnimg.cn/blog_migrate/ec00a5005682d0cb86ce3fe5e488735a.jpeg)
这里的__index 元表允许下面的情况:当我们提供英语单词时给出相应的德语单词,如果没有找到合适的翻译,就展示默认的英语单词。
使用函数:
除了使用表作为 __index 条目之外,你还可以指定一个函数,其两个 参数即表和键。 这个函数允许你在表的索引中添加逻辑,并且当和__newindex 元方法 成对出现时, 你可以做很多有趣的事,比如创建一个只读表。现在,运行下面代码,它将提示你在代码中哪些符号是无效的。
![](https://i-blog.csdnimg.cn/blog_migrate/7604053e249067a10c515062d59558a7.jpeg)
![](https://i-blog.csdnimg.cn/blog_migrate/a6c3cb7c32a727738fdbe3d834e8a653.jpeg)
[6]使用_ _newindex 引出新的键
__index 元方法有3 个参数:
foride : 需要索引的表
key : 索引表用到的键
value : table [key] 所分配的值
当设置新的键时,函数能通知你,它甚至能防止键被重复设置。当设置这种元方法后,它会对这种分配做出响应。下面的例子将允许你设置除 “banana” 外的任何索引值。
![](https://i-blog.csdnimg.cn/blog_migrate/cc9f657fb16a6eed9dd794a0f1b3d419.jpeg)
当这个项被设置后,在3个表中的任意一个中,你都不能(通过传统途径)设置键 [ " banana " ]
![](https://i-blog.csdnimg.cn/blog_migrate/5dfeb36096976a94434d264166995240.jpeg)
由于error() 完全阻止了这个函数,因此不能设置该项,这相当于在表中拥有了一个虚拟的 ”受保护的“键
(3)旁路元表
(1) 创建和索引表
在Lua中 {} 表示创建一个表 ,本例创建的是一个空表
alice ={}
hello=alice
print(alice)
print(hello)
hello 和alice 指向同一个地址
![](https://i-blog.csdnimg.cn/blog_migrate/23ae5146abefc34055d309bfbcabee6d.jpeg)
、、、、、、、、、、、、、、、、、、、、
实际上,Lua允许使用除nil以外的任何值作为关键词
foride ={}
hello=foride
print(foride)
print(hello)
foride["name"]= "lisong"
foride["phone"]="13592635..."
foride["address"]="郑州市中原区。。。"
print(foride.name)
print(foride.phone)
print(foride.address)
print("--------------")
print(foride["name"])
print(foride["phone"])
print(foride["address"])
print("-------------")
foride[1]="这是一个测试"
foride[2]=6688
print(foride[1])
print(foride[2])
![](https://i-blog.csdnimg.cn/blog_migrate/5fc8b3aed7a9e0056bdade3ad4f3ee97.jpeg)
如下使用一个函数的地址作为关键词
foride ={}
hello=foride
print(foride)
print(hello)
--//==================
func=function ()
print("hello")
end
func()
print(func)
test=function ()
print("test")
end
test()
print(test)
foride[func]=test
print(foride[func])
foride[func]() --//只能通过[] 的方式
![](https://i-blog.csdnimg.cn/blog_migrate/a7d62b8e5b13be6278087e65737550f7.jpeg)
(2)从表中清除元素
未被定义的关键字(如下 fax)索引的时候,表将返回一个特定的值nil 。
foride ={}
foride[1]="这是一个测试"
foride[2]=6688
print(foride[1])
print(foride[2])
print("-----------")
print(foride.fax)
print(foride[3])
print("----------")
foride[1]=nil
foride[2]=nil
print(foride[1])
print(foride[2])
![](https://i-blog.csdnimg.cn/blog_migrate/6230df05b755e3fe2c2f008e9b754d9d.jpeg)
(3)字符串关键字的快捷方式
例如如下代码
print(foride.name)
print(foride.phone)
print(foride.address)
print("--------------")
print(foride["name"])
print(foride["phone"])
print(foride["address"])
这种快捷的方式只有当关键词以字母或者下划线字符开头,并且只有字母、数字、下划线组成的时候才能执行。此外,关键词不能是Lua的保留关键字(如end)。
使用 [ ] 标记可以索引以数字开始的关键词
![](https://i-blog.csdnimg.cn/blog_migrate/4b3042cab7cd178915fa81425cfa0ddf.jpeg)
![](https://i-blog.csdnimg.cn/blog_migrate/0da11d879c70e80d723e0a0f128b9dfa.jpeg)
(4)创建有内容的表
foride ={
["name"]= "lisong",
["phone"]="13592635..." ,
["address"]="郑州市中原区。。。",
}
foride ={
name= "lisong",
phone="13592635..." ,
address="郑州市中原区。。。",
}
每一个例子的最后在结束之前都有一个逗号。
【2】把表当做数组使用
(1) 创建数组
foride={
value1,
value2,
value3,
value4
}
foride={
[1]=value1,
[2]=value2,
[3]=value3,
[4]=value4
}
数组是表的一种特殊情况。这部分所涉及的函数,只在处理从1开始的连续整数关键字时是可靠的。
![](https://i-blog.csdnimg.cn/blog_migrate/b4d1f743fd88936a6df3286ad80f4343.jpeg)
![](https://i-blog.csdnimg.cn/blog_migrate/d6fce9f21406171e2506d4d888136f0b.jpeg)
(2)获取数组的长度
![](https://i-blog.csdnimg.cn/blog_migrate/7ac2427be8e74365ec9cdac632d1a639.jpeg)
输出: 5
![](https://i-blog.csdnimg.cn/blog_migrate/350b0ef6eaab4569aa7ec9b602c9fb2f.jpeg)
如下是一个空表
![](https://i-blog.csdnimg.cn/blog_migrate/0db948abe464f12c84d115e9d700a63e.jpeg)
![](https://i-blog.csdnimg.cn/blog_migrate/26625f15691a80698b716244118664f8.jpeg)
如下程序:
![](https://i-blog.csdnimg.cn/blog_migrate/6f43af0352c80e2fb32ba8ceeffd6f99.jpeg)
![](https://i-blog.csdnimg.cn/blog_migrate/17851d32676f5d211697946db9c300fb.jpeg)
运行结果
![](https://i-blog.csdnimg.cn/blog_migrate/b406843ee9ed8b2ccfea536a43262698.jpeg)
(3)在数组中添加元素
Lua提供了一个标准的table.insert() 库函数,可以让添加数组元素变得更加简单。 table.insert()的语法是:
table.insert( foride , [ pos ,] value)
foride : 被修改的表
pos :添加元素所在的位置
value : 添加元素的值
![](https://i-blog.csdnimg.cn/blog_migrate/3f1578a44ab34ec91ff9d30066bc5c7a.jpeg)
![](https://i-blog.csdnimg.cn/blog_migrate/c874cde54ead1ef14330d284e81662f8.jpeg)
在调用print_table 函数前 , 添加如下两行代码
(1-1)自动在列表的末尾添加新的元素
![](https://i-blog.csdnimg.cn/blog_migrate/783b6f1c7fd8bbc3e627d67d4e59397d.jpeg)
![](https://i-blog.csdnimg.cn/blog_migrate/42969dd69c75fa8c35d36ca685428d31.jpeg)
(1-2)在指定位置添加新的元素
![](https://i-blog.csdnimg.cn/blog_migrate/44873e3aed063aebb7faacfa22440edc.jpeg)
运行结果如下:
![](https://i-blog.csdnimg.cn/blog_migrate/d3e38bcb5411a9531c6181e399335960.jpeg)
(1-3)
![](https://i-blog.csdnimg.cn/blog_migrate/6618760f3db478b504be5e17237773f9.jpeg)
![](https://i-blog.csdnimg.cn/blog_migrate/843efab7d349fd99f751b5d68a10e737.jpeg)
(4)从数组中删除元素
Lua包含一个能从表中删除元素的函数
value =table.remove( foride , [ , pos] )
foride : 被修改的表
pos : 被移除元素所在的位置
value : 被删除的值
如下的程序: 移除了 foride 表中的最后一个 Nginx 和 第一个元素 Linux
![](https://i-blog.csdnimg.cn/blog_migrate/e2a063d0c69d067923fbc1eadb8e8236.jpeg)
![](https://i-blog.csdnimg.cn/blog_migrate/ab8689caf2a0a26a1faab39db4a43a8b.jpeg)
(5) 对数组中的元素排序
table.sort() 的语法遵循:
table.sort( foride [ , comp ] )
table.sort() 的第二个参数在下一篇介绍
![](https://i-blog.csdnimg.cn/blog_migrate/42b9e2e86403ea6160c99c5e5520b486.jpeg)
![](https://i-blog.csdnimg.cn/blog_migrate/01660f30eb1b84119e6d43fc336d7952.jpeg)
上面的例子:因为表中的变量都是字符串,因此它们将会按字母顺序升序排列(默认)。如果包含的是数字,则排序方式相同。
如果遇到一些更加复杂的值(如表)。或者数组中的值是混合的(如字符串和数字),像这种简单的排序方式的效率就非常的低,table.sort() 的第二个参数允许你修改排序函数,因此它能够适应这种复杂的情况
【3】 用名称空间使用表
(1)创建 foride 名称空间
通过定义一个表,创建一个名称空间,以便存储函数
foride = { }
(2)向 foride 中添加函数
[1-1] 存储已有函数
![](https://i-blog.csdnimg.cn/blog_migrate/9b1dce908bd4215143c0019393c1d382.jpeg)
![](https://i-blog.csdnimg.cn/blog_migrate/c14d0099d1c85a46b7cb01e6ad0e5fac.jpeg)
[1-2] 定义新函数
第一种形式通常是定义函数的最方便的方式。比起另一种,它的可读性更强。
![](https://i-blog.csdnimg.cn/blog_migrate/d5881222e694b803574219408f8432f2.jpeg)
【4】 表的面向对象编程
(1)创建非面向对象计数器
![](https://i-blog.csdnimg.cn/blog_migrate/00a1671fd79a3e07b0881beae226b9f4.jpeg)
![](https://i-blog.csdnimg.cn/blog_migrate/003542b16a8530f3932d804a1c834778.jpeg)
(2)把表作为简单的对象
//=========================================================================
![](https://i-blog.csdnimg.cn/blog_migrate/950ec86510d884e21ab82d0e6b2d9c4f.jpeg)
![](https://i-blog.csdnimg.cn/blog_migrate/e8ef007081e0096bf1856311d03212e8.jpeg)
//=========================================================================
在这个现实中,实际的计数器变量存储在一个表中(以对象形式)。与值交互的每一个函数都有一个名为self的参数,其被作为计数器对象。我们可以通过运行一下代码创建一个新的计数器。
![](https://i-blog.csdnimg.cn/blog_migrate/44c4fc2f461f510550d5d60e128d9fe8.jpeg)
![](https://i-blog.csdnimg.cn/blog_migrate/0a0cea16995e8d7b3d7770cb98c8ae72.jpeg)
因为这些函数只是Lua 值,并且他们是通过参数而不是一些神秘的隐藏变量进行工作的,所以你可以把他们复制到新的计数器中。事实上,即使把他们混合在一起,函数也能正常工作。
![](https://i-blog.csdnimg.cn/blog_migrate/2dadec37f5920326fda83374dd200648.jpeg)
![](https://i-blog.csdnimg.cn/blog_migrate/99cbe7b96e7bb2ca6891939c89640399.jpeg)
(3)冒号调用对象方法
当调用一个对象的方法的时候,你可以使用冒号来代替句点,这个对象将会作为方法的第一个参数传递。意味着你可以调用foirde:get() 来代替 foride.get(foride) 。这个在后台自动运行的功能可以防止在每次调用方法时都要传递一次对象。
(4)用冒号定义函数
function tb1:MyModth() end 和 function tb1.MyModth(self) end 方法等价
![](https://i-blog.csdnimg.cn/blog_migrate/ed9b0062df22a2ac0b4461492b8b674e.jpeg)
![](https://i-blog.csdnimg.cn/blog_migrate/fb48220a7209cb3564ca28390eb98a31.jpeg)
(5)创建更佳的计数器
![](https://i-blog.csdnimg.cn/blog_migrate/72552f98c3523f016efe78e5583a5100.jpeg)
![](https://i-blog.csdnimg.cn/blog_migrate/13ba3c735861e9680b648703d52aab94.jpeg)
【‘5】利用元素对表进行扩展
在Lua中的每一个表都能够附带一个元表 (metatable)。 元表是一种二级表格。它提供了一些关于表应当该如何处理的附加信息。
(1)添加元表
元表是一个简单的表,它存储了和它有联系的的表的一些附加信息。他们能够被传递,能够被附加到很多表,并且随时可以更改。
为了重新定义表的行为,你必须创建一个元表,然后利用setmetatable() 函数将其附加到一个表对象。
这个函数有两个参数:
foride1 : 待改变的表
mt : 附加到foride1 的表
另外,setmetatable() 函数只返回一个参数,即作为第一个参数传入的表。当新建一个表来直接传递给 setmetatable() 时,这会相当有帮助。
运行下面的代码创建一些表,并且在每一个表上附加同样的元表(mt)。
可以使用getmetatable() 函数来验证元表是否已成功建立,这个函数将表作为第一个参数,返回一个元表。当没有元表时,它返回nil 。
![](https://i-blog.csdnimg.cn/blog_migrate/4da32d8cdfc017af973f2f99c5aae20f.jpeg)
![](https://i-blog.csdnimg.cn/blog_migrate/613350e77dba0d68ecda9eae9a675925.jpeg)
(2)定义元方法
元方法(metamethod)其实是一个函数,它存储在元表中,且带有一个给定的键。元方法有很多种,其参数各不相同,每一个元方法都以两个下划线开头。
常用的元方法
元方法 参数个数 描述
------------------------------------------------------------------------------------------------------------------------------------------------------------
_ _add 2 定义加法的行为
------------------------------------------------------------------------------------------------------------------------------------------------------------
_ _mul 2 定义乘法的行为
------------------------------------------------------------------------------------------------------------------------------------------------------------
_ _div 2 定义除法的行为
------------------------------------------------------------------------------------------------------------------------------------------------------------
_ _sub 2 定义减法的行为
------------------------------------------------------------------------------------------------------------------------------------------------------------
_ _unm 1 定义非的行为(一元减法)
------------------------------------------------------------------------------------------------------------------------------------------------------------
_ _tostring 1 定义当表是tostring() 的参数时的行为,它也会影响到
直接调用tostring() 的print()函数
------------------------------------------------------------------------------------------------------------------------------------------------------------
_ _concat 2 定义当使用连接操作时的行为
------------------------------------------------------------------------------------------------------------------------------------------------------------
_ _index 2 定义当表用该表不存在的键检索时的行为
------------------------------------------------------------------------------------------------------------------------------------------------------------
_ _newindex 3 定义当用表中未预先设置的键检索时的行为
------------------------------------------------------------------------------------------------------------------------------------------------------------
[1] 使用 _ _add, _ _sub, _ _mul 和 _ _div 定义基本运算
![](https://i-blog.csdnimg.cn/blog_migrate/45851ea3061e84ae41d7f4095edfbb7e.jpeg)
![](https://i-blog.csdnimg.cn/blog_migrate/b2d67d24aa00938505873ca45a0a8ffd.jpeg)
[2]使用 _ _unm 定义负运算
![](https://i-blog.csdnimg.cn/blog_migrate/eb4dcf50fc36b63c15d8907036758bf6.jpeg)
![](https://i-blog.csdnimg.cn/blog_migrate/50d4d7226cd7154eaa7b271713895276.jpeg)
[3]使用 _ _tostring 建立有意义的输出
![](https://i-blog.csdnimg.cn/blog_migrate/45920bb188729e23a3e85946cce27dbf.jpeg)
![](https://i-blog.csdnimg.cn/blog_migrate/5a21aa0a9c745864389059ed032e6b3a.jpeg)
[4] 使用 _ _concat 连接表
对于表,连接运算了加法运算一样,所以你可以使用同样的函数来构造__concat 元方法。
两个方法都带有两个参数,一个返回值。另外,两者都是典型的连锁式运算,所以你要确保你的结果也能连接上。
![](https://i-blog.csdnimg.cn/blog_migrate/dd302b260ea3c7906d5b9583e7ca76b0.jpeg)
因为__tostring 元方法仍然处于激活状态,结果表被转化为串表达式,甚至显示也是如此
![](https://i-blog.csdnimg.cn/blog_migrate/c4a1f0e80a64a29f9037f396ba1f3e41.jpeg)
[5]使用 _ _index 在后备表中浏览
一般来说,当所要查找的键没有和表中的任意一个值相关联时,将返回nil。 然而,在一般情况下,其他的返回值会更有意义, __index 是允许这种情况出现的。以下就是当索引没有找到时所发生的。
(1)表使用一个没有相关值的键来进行索引
(2) 如果表的__index元表项是一个表,就返回那个表中键所对应的项(当不存在时,返回nil)
(3)如果表有__index元表项,就返回这个表调用函数的结果,以键值作为参数。
表的使用如下:
![](https://i-blog.csdnimg.cn/blog_migrate/51a0b14c1e2806f685c6afcb71c2cc5b.jpeg)
这个例子创建了一个表,包含着用于德国服务器的英语短语 “Night elf” 。 另外,有一个默认的表包含一些英语短语 ”Human“和 “Night elf”.。 当检索表deDE_races 时,如果没有找到答案,Lua 就顺便访问元表的 __index 项, 然后返回结果。
![](https://i-blog.csdnimg.cn/blog_migrate/ec00a5005682d0cb86ce3fe5e488735a.jpeg)
这里的__index 元表允许下面的情况:当我们提供英语单词时给出相应的德语单词,如果没有找到合适的翻译,就展示默认的英语单词。
使用函数:
除了使用表作为 __index 条目之外,你还可以指定一个函数,其两个 参数即表和键。 这个函数允许你在表的索引中添加逻辑,并且当和__newindex 元方法 成对出现时, 你可以做很多有趣的事,比如创建一个只读表。现在,运行下面代码,它将提示你在代码中哪些符号是无效的。
![](https://i-blog.csdnimg.cn/blog_migrate/7604053e249067a10c515062d59558a7.jpeg)
![](https://i-blog.csdnimg.cn/blog_migrate/a6c3cb7c32a727738fdbe3d834e8a653.jpeg)
[6]使用_ _newindex 引出新的键
__index 元方法有3 个参数:
foride : 需要索引的表
key : 索引表用到的键
value : table [key] 所分配的值
当设置新的键时,函数能通知你,它甚至能防止键被重复设置。当设置这种元方法后,它会对这种分配做出响应。下面的例子将允许你设置除 “banana” 外的任何索引值。
![](https://i-blog.csdnimg.cn/blog_migrate/cc9f657fb16a6eed9dd794a0f1b3d419.jpeg)
当这个项被设置后,在3个表中的任意一个中,你都不能(通过传统途径)设置键 [ " banana " ]
![](https://i-blog.csdnimg.cn/blog_migrate/5dfeb36096976a94434d264166995240.jpeg)
由于error() 完全阻止了这个函数,因此不能设置该项,这相当于在表中拥有了一个虚拟的 ”受保护的“键
(3)旁路元表
当为__index 和 __newindex 元方法编写函数时,特别的,获取值时必须忽略元表,这由 rawget() 和rawset() 函数完成。
value=rawget(foride,key)
rawget()函数用待查询的表以及键作为参数,返回在查询表中没有使用元表的键值。编写作为表的元方法的函数时,做好使用rawget() 来获取在同一表中的值。
rawset(foride,key,value)
为了使表中的设置不与元表冲突,可以使用rawset() 函数。这个函数的参数包括要改变的表,将用到的键和需要置于表中的值。
相当于 __newindex 元方法,你将会遇到更多使用 __index 元方法的表,但是 最好要明确,哪种工具在你需要时可以使用。