lua元表介绍

元表主要用来和表关联,但因为其特性的关系,可以用来编写lua中特有的类,接下来就介绍一下lua 元表中的元方法(需要注意前面不是一个下划线,是两个,一个lua不会认为是元方法的)

1.__index
这个方法是用来获取值的,也就是表查询,在lua中对表的查询过程大致是这样的,首先会对表中的索引进行查找,没有就继续查找元表中__index中的方法,如果__index是张表,就继续照如上步骤进行,如果__index是个方法的话,则返回函数的返回值,函数参数则为该表和字段,下面是个列子:

a={};
b={__index={s=1}}
//不设置元表,查询
a.s ---结果为nil
//设置元表
setmetatable(a,b);
a.s ———结果为1
b={s=1}
//依然设置元表
a.s ---结果为nil
b.__index=function(t,k) if(k=="s") then
return 3; else return 4 end end
//设置元表
a.s-----3
a.e-----4

2.__newindex
该方法为赋值方法,也就是说给lua的表赋值时,依然和__index一样,首先查找表中索引,在查找__newindex的索引如果是张表的话,是函数的话,也和__index是一样的,只是参数部分多加了value,就是a.s=3等号右边的部分
列子

a={}
b={__newindex={}}
setmetatable(a,b)
a.s=3
print(a.s)   --nil
print(b.__newindex.s) --3
//函数
b.__newindex=function(t,k,v)
if type(v)=="number" then
 rawset(t,k,v*v)
else
  rawset(t,k,v);
 setmetatable(a,b)
 end
 end
a.s=7
a.e="b"
print(a.s);    49
print(a.e);     b

看完列子后是不是觉得很疑惑,明明是给a.s赋值了,为什么还是nil了,因为lua在查询a.s时在表中并没有该索引,所以实际上lua在此时并没有进行赋值,而是继续查找__newindex并在这里面进行了赋值,而在函数部分是使用了rawset来进行赋值,这是为了避免陷入无限循环,rawset和rawget是无视__index和__newindex进行赋值和取值的函数,在上面的例子中如果用t[k]=v*v来进行赋值则又会进入__newindex中来赋值,然后无限循环下去,所以使用rawset来避免使用__newindex从而达到赋值目的

3.运算方法,加减乘除等元方法
__mul 乘法
__add 加法
__sub 减法
__div 除法
__mod 取模
__unm 取反
__concat:连接
__eq 等于(==)
__lt 小于(<)
__le 小于等于(<=)
这些元方法会在稍后的lua”类”的例子中一起写出来

4__call
这个可以用来实现构造方法,使用的情况是表名(参数)这种,传入参数是表和要传入的值例子如下:

a={}
b={}
b.__call=function(t,a,b,c,d)
return (a+b+d)*c
end
setmetatable(a,b)
print(a(1,2,3,5))  24
可以看成是直接把表当做函数来使用

5.__tostring
这个主要是打印时使用,主要目的是把元素转为字符串列子,传入参数依然是本表

a={s=1,e=2,c=3}
b={}
b.__tostring=function(t)
sum=0
sum=sum+t.s+t.e+t.c
return "sum:"..sum
end
setmetatable(a,b)
print(a);    sum:6

6.上面已经介绍了基本的一些元方法,下面就是实战了,用这些方法来实现一个“类”,因为lua的8种数据类型中并不包含类的实现,所以这里需要用到元表的方式来实现,首先来介绍一个语法糖,下面会用到

定义成function t.method(a,b,c) end,其实质是定义的t.method(self,a,b,c),self指向自身

people={}
people.__index=people//注意要将__index赋给自己,这样才能使之后定义的对象能够从__index中拿到方法
function people.new(x,y)
    newObj={name=x,age=y}
    return setmetatable(newObj,people);
end
function people.__tostring(b)
    return "My Name is"..b.name.."My Age is"..b.age

end
function people.__add(a,b)
     if(type(a)=="number") then
         return ;
      elseif(type(b)=="number") then
         return ;
    else
         return people.new(a.name.."."..b.name,a.age+b.age);

    end
end
function people.__mul(a,b)
     if(type(a)=="number") then
         return ;
      elseif(type(b)=="number") then
         return ;
    else
         return people.new(a.name.."."..b.name,a.age*b.age);

    end
end
function people.__div(a,b)
     if(type(a)=="number") then
         return ;
      elseif(type(b)=="number") then
         return ;
    else
         return people.new(a.name.."."..b.name,a.age/b.age);

    end
end
function people.__sub(a,b)
     if(type(a)=="number") then
         return ;
      elseif(type(b)=="number") then
         return ;
    else
         return people.new(a.name.."."..b.name,a.age-b.age);

    end
end
function people.__unm(a)
     if(type(a)=="number") then
         return ;
      elseif(type(b)=="number") then
         return ;
    else
         return people.new(a.name,-a.age);

    end
end
function people.__eq(a,b)
     if(type(a)=="number") then
         return false;
      elseif(type(b)=="number") then
         return false;
    else
         if a.name==b.name and a.age==b.age then
         return true
         else
          return false
          end

    end
end
function people.__lt(a,b)
     if(type(a)=="number") then
         return false;
      elseif(type(b)=="number") then
         return false;
    else
         if  a.age<b.age then
         return true
         else
          return false
          end

    end
end
function people.__mod(a,b)
     if(type(a)=="number") then
         return ;
      elseif(type(b)=="number") then
         return ;
    else
        return people.new(a.name.."."..b.name,a.age%b.age);

    end
end
setmetatable(people, { __call = function (_, ...)

        return people.new(...);

end
})
b=people.new("hank",17);
c=people.new("wesker",21);
print(b.name,b.age)
print(b)
print(c)
print(b+c)
print(b*c)
print(b/c)
print(b-c)
print(-b)
print(b==c)
print(b<c)
print(b%c)

d=people("ada",23)
print(d)

上面就是一个简单的类实现,同时这种类的实现并不拘泥于元方法,用户也可以自定义方法,lua的元表使用方式也不仅仅是这样,同样在于C++交互时也可以用来承载C++的类,所以对于元表来说,是必须要掌握的

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章