深入理解Lua中的元表setmetatable

980 词

一直对Lua中的元表理解的不是很深,今天刚好有时间重点看了一下这一部分,写一下笔记有利于日后翻阅

Lua中的表

Lua是“万物基于表的”,Table既可以模拟数组,也可以模拟字典哈希表等,确实很强大。其实Lua表的本质就类似是我们C#中的字典,是以很多键值对存在的。如果访问了一个表中并不存在的一个元素时就会触发Lua中的一套查找机制,Lua中继承的模拟也是运用了这一机制。

元表

元表像是一个“操作指南”,里面包含了一系列操作的解决方案,例如__index方法就是定义了这个表在索引失败的情况下该怎么办。

元方法 __index

index可以指向一个元素,如果说元表是个指南针,那么index是指向的具体方位,如果只有指南针是不够的,你还是不知道具体的方位。例如把A设置成B的元表,如果不设置__index,想要用B去访问A中的方法时,返回的还是nil,例如下面的例子很好的证明了这一点。

1
2
3
local A = {name = "zz"}
tb = setmetatable({},A)
print(tb.name)

这时候换种思路,指定A的元方法为自己:

1
2
3
4
local A = {name = "zz"}
A.__index = A
tb = setmetatable({},A)
print(tb.name) -- 结果为 zz

一般会写成下面这样:

1
2
3
local A = {name = "zz"}
tb = setmetatable({},{__index = A})
print(tb.name) -- 结果为 zz

由此可以看出,当把A设置成一个空表的元表时,当我们用tb.name访问A中的name时,lua并不是直接在A中查找name这个元素,而是调用A中的index,如果index为空时,那么就会返回nil

总结

index方法除了可以是一个表,还可以是一个函数,如果是一个函数,index方法被调用时将返回该函数的返回值。而操作步骤可以分为三步:

  • 在表中查找,如果找到,返回该元素,找不到则继续
  • 判断该表是否有元表(操作指南),如果没有元表,返回nil,有元表则继续
  • 判断元表(操作指南)中有没有关于索引失败的指南(即index方法),如果没有(即index方法为nil),则返回nil;如果index方法是一个表,则重复1、2、3;如果index方法是一个函数,则返回该函数的返回值