Lua元表(Metatable)

元表这个词听起来就觉得抽象,我开始接触Lua的时候就是这种感觉。其实不要被表面吓到。

元表就是,如果一个tableB 调用setmetatable方法设置另外一个tableA作为它的元表,那么当你操作tableB进行如设置键值,查找键值,table间使用运算符号、或者直接传个参数调用等操作时就会变得不一样或者原本不可行操作的现在可行了。而tableA之所以能作为元表,是因为里面包含了特殊的键代表着特殊的含义,代码在运行时会做特殊的处理,下面会一一做介绍。

首先记住两个函数:

    setmetatable(table,metatable)

对指定table设置元表(metatable),如果元表(metatable)中存在__metatable键值,setmetatable会失败 。

      getmetatable(table)

返回对象的元表(metatable)。如元表中存在__metatable键值,返回元表会失败

    __metatable键值是用于安全考虑,可以防止获取和修改元表中的内容。

下面实例演示如何设置元表

      metatable= {}    ---- 元表

      table= {}    ----普通表

      setmetatable(table,metatable)    ----将metatable设置为table的元表

也可以直接这么写

  setmetable({},{})

返回元表

     getmetatable(table)     -----返回metatable


1、访问与设值

        __index键

        当你通过一个键访问table的时候,如果这个table中没有这个键值对,但它设置了元表,且元 表中有__index这个键,如果__index的值为一个表,那么程序就会到这个表中去查找,如果__index的值为一个函数,那么程序就会 调用这个函数。看代码

local tableA = {k2 = "Hello"}

  local tableB = {k1 = "Hi"}

  setmetatable(tableB,{__index = tableA})

  print(tableB.k2)

打印:

Hello                

__index 值为函数

function fn (table,key)            

    print(table,"\n",key)

    return "Hello"

  end

  local tableB = {k1 = "Hi"}

  setmetatable(tableB,{__index = fn})      ----会将table 和 key作为参数传给fn

  print(tableB.k2)

打印:

table: 000000000067a690

k2

Hello


__newindex键

     __index用于访问,__newindex用于设置新值。当一个table设置了元表,为这个table设置键值的时候,如果这个键存在,那么直接修改当前键值;如果这个键不存在,那么会操作元表中__newindex相应的值。__newindex的值为一个table或者函数。看如下代码

    local tableA = {}

    local tableB = setmetatable({k1 = "Hi"},{__newindex = tableA})

    tableB.k1 = "HiHi"

    tableB.k2 = "Hello"

    print(tableB.k1,tableB.k2,tableA.k2)

打印结果:

HiHi   nil   Hello      -------tableA 被设置了一个新值

__newindex的值为函数:

function fn (table,key,value)

    print(table,"\n",key,"\n",value)

  end

  local tableB = {k1 = "Hi"}

  setmetatable(tableB,{__newindex = fn})    ---会将table、key、value传给fn作为参数

  tableB.k2 = "Good"

打印结果:

table: 000000000256a650

k2

Good

温馨提示:以上例子都是通过一个key访问具体值,如果这个key为一个方法也是同样试用的,自己没有会到元表中去操作。

2、运算符

    当我们想table与table之间使用“+、-、*、/、==、<=”等运算时,就得通过元表来实现。以”+“为例,对应的元方法为__add,看如下代码,实现table1+table2 输出一个newtable,newtable中的元素为table1与table2的和,  看如下代码 :

local table1 = {1,2,3}

local table2 = {4,5,6}

local fn = function (t1,t2)          -----table会被传入作为参数

  local newtable = {}

  for i=1,3 do

    newtable[i] = t1[i] + t2[i]

  end

  return newtable

end

setmetatable(table2,{__add = fn})

local newtable = table1+table2

for k,v in pairs(newtable) do

  print("newtable --",k,v)

end

打印结果:

newtable -- 1    5

newtable -- 2    7

newtable -- 3    9

两表相加,必须至少其中一个表设置了带__add键的元表,否侧会报错(其他运算符同理),程序会执行__add对应的函数。如果两个表都设置了有__add键的元表,程序会去执行“+”左侧的表中的元表的__add对应的函数。

其他运算符:

3、调用

 __call键

     我们可以直接像调用普通方法一样传入参数直接调用table,但前提是table设置了元表,并且元表中有__call键。看代码:

local table = {1,2,3}

  local sum = 0

  local fn = function (t,v)        ----table会作为第一个参数,其他的为传入的参数

    for i=1,#t do

        sum =sum+ t[i] *v        ----将table中的每一个元素*5 再相加求和

    end

    return sum

  end

  setmetatable(table,{__call = fn})

  print(table(5))      -----调用table,传入一个参数5(可以传入多个参数)

打印结果:

30

4、自定义打印

    __tostring键

    可以自定义table的输出行为,看如下代码:

local table = {key1 = "a" ,ke2 = "b" ,ke3 = "c"}

  local  fn = function (t)           ----table会作为参数传入

       return "Hello here"

  end

  setmetatable(table,{__tostring = fn})

  print(table)

打印结果:

Hello here

        

以上就是元表的相关介绍。

最后编辑于
©著作权归作者所有,转载或内容合作请联系作者
禁止转载,如需转载请通过简信或评论联系作者。
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 212,080评论 6 493
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 90,422评论 3 385
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 157,630评论 0 348
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 56,554评论 1 284
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 65,662评论 6 386
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 49,856评论 1 290
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 39,014评论 3 408
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 37,752评论 0 268
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 44,212评论 1 303
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 36,541评论 2 327
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 38,687评论 1 341
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 34,347评论 4 331
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 39,973评论 3 315
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 30,777评论 0 21
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 32,006评论 1 266
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 46,406评论 2 360
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 43,576评论 2 349

推荐阅读更多精彩内容