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++的類,所以對於元表來說,是必須要掌握的

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