[Lua]Lua高級教程Metatables


什么是Metatable

metatable是Lua中的重要概念,每一個table都可以加上metatable,以改變相應的table的行為。

Metatables舉例

-- 聲明一個正常的關系變量
lo_table = {} 

-- 聲明空元表變量
lo_meta_table = {}

-- 為關系變量t設置元表變量
setmetatable(lo_table, lo_meta_table) 

-- 獲取一個關系變量的元表變量
getmetatable(lo_table)

上邊的代碼也可以寫成一行,如下所示

-- setmetatable函數的返回值,就是該函數的第一個參數
lo_table = setmetatable({}, {})

創建復雜的元表變量

metatable可以包括任何東西,metatable特有的鍵一般以__開頭,例如__index__newindex,它們的值一般是函數或其他table。

lo_table = setmetatable({}, {
  __index = function(lo_table, key)
    if key == "foo" then
      return 0
    else
      return table[key]
    end
  end
})

__index

  這是metatable最常用的鍵了。

  當你通過鍵來訪問table的時候,如果這個鍵沒有值,那么Lua就會尋找該table的metatable(假定有metatable)中的__index鍵。如果__index包含一個表格,Lua會在表格中查找相應的鍵。

-- 創建元表變量
lo_meta_table = { name = "藍鷗" }

-- 設置該元表變量作為關系變量的
lo_table = setmetatable({}, { __index = lo_meta_table })

-- 打印lo_table變量的姓名 藍鷗
print(lo_table.name)

-- 打印lo_table變量年齡 nil
print(lo_table.age)

  如果__index包含一個函數的話,Lua就會調用那個函數,table和鍵會作為參數傳遞給函數。

-- 創建元表變量
lo_meta_table = { 
    name = "藍鷗" ,
    action = function ( param )
        -- body
        if(param == "學生") then
            print("讓教育回歸本質")
        else
            print("讓藍鷗維護教育")
        end
    end
}



-- 設置該元表變量作為關系變量的
lo_table = setmetatable({}, { __index = lo_meta_table })

-- 打印lo_table變量的動作 讓教育回歸本質
print(lo_table.action("學生"))

-- 打印lo_table變量的動作 讓藍鷗維護教育
print(lo_table.action("肖浩"))

-- 打印lo_table變量年齡 nil
print(lo_table.age)

 

__newindex

類似__index__newindex的值為函數或table,用於按鍵賦值的情況。

-- 創建元表變量
lo_meta_table = {}

-- 設置該元表變量作為關系變量的
lo_table = setmetatable({}, { __newindex = lo_meta_table })

-- 設置lo_table變量的name關鍵字的值
lo_table.name = "藍鷗"

-- 打印lo_meta_table元表變量name關鍵字的值值
print(lo_meta_table.name)

-- 打印lo_table變量name關鍵字的值
print(lo_table.name)

 

-- 創建元表變量
lo_meta_table = {}

-- 設置該元表變量作為關系變量的
lo_table = setmetatable({}, { __newindex = function(t, key, value)
    if type(value) == "number" then
      rawset(t, key, value * value)
    else
      rawset(t, key, value)
    end
  end
})

-- 設置lo_table變量的name關鍵字的值
lo_table.name = "藍鷗"

-- 設置lo_table變量的age關鍵字的值
lo_table.age = 3

-- 打印lo_meta_table元表變量name關鍵字的值值
print(lo_meta_table.name)

-- 打印lo_table變量name關鍵字的值
print(lo_table.name)

-- 打印lo_meta_table元表變量age關鍵字的值值
print(lo_meta_table.age)

-- 打印lo_table變量age關鍵字的值
print(lo_table.age)

上面的代碼中使用了rawgetrawset以避免死循環。使用這兩個函數,可以避免Lua使用__index__newindex

運算符

利用metatable可以定義運算符,例如+

-- 創建重載+號行為的表變量
lo_table = setmetatable({ 1, 2, 3 }, {
  __add = function(lo_table, other)
    new = {}

    -- 遍歷元素加other
    for _, v in ipairs(lo_table) 
        do table.insert(new, v + other) 
    end

    return new
  end
})

-- 進行計算+
lo_table = lo_table + 2


-- 打印得到的結果
print(lo_table[1])
print(lo_table[2])
print(lo_table[3])

__index__newindex不同,__mul的值只能是函數。與__mul類似的鍵有:

  • __add (+)
  • __sub (-)
  • __div (/)
  • __mod (%)
  • __unm 取負
  • __concat (..)
  • __eq (==)
  • __lt (<)
  • __le (<=)

 

__call

__call使得你可以像調用函數一樣調用table

t = setmetatable({}, {
  __call = function(t, a, b, c, whatever)
    return (a + b + c) * whatever
  end
})

local result = t(1, 2, 3, 4)
print(result)

 

__tostring

最后講下__tostring,它可以定義如何將一個table轉換成字符串,經常和 print 配合使用,因為默認情況下,你打印table的時候會顯示 table: 0x7f86f3d04d80 這樣的代碼

lo_table = setmetatable({ 1, 2, 3 }, {
  __tostring = function(lo_table)
    sum = 0
    for _, v in pairs(lo_table) 
    do 
        sum = sum + v 
    end
    
    return "計算的結果是: " .. sum
  end
})

-- prints out "計算的結果是: 6" 
print(lo_table)        

 

創建一個簡單的向量Vector類

Vector = {}
Vector.__index = Vector

function Vector.new(x, y)
  return setmetatable({ x = x or 0, y = y or 0 }, Vector)
end

-- __call關鍵字
setmetatable(Vector, { __call = function(_, ...) return Vector.new(...) end })


-- + 運算符
function Vector:__add(other)
  -- ...
     local result = Vector(self.x + other.x,self.y + other.y)

     return result
end

-- __tostring關鍵字
function Vector:__tostring()
    -- body

    return "x: " .. self.x .. " y: " .. self.y

end

a = Vector.new(12, 10)
b = Vector(20, 11)
c = a + b

print(a)
print(c)

 

原文鏈接:http://nova-fusion.com/2011/06/30/lua-metatables-tutorial/


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM