lua入门教程:第十一章 lua中Metatables的使用

Metatable和表

在使用lua的时候,lua 的表是最经常用到的,虽然表已经提供给我们非常多的操作,包括变量,函数等,Metatable的引入可以改变相应的表行为,使得表更加的灵活。

有时我们需要对表中新创建的元素进行跟踪,使用Metatable可方便的做到这一点。带着这个问题,看看是如何使用Metatable 做到这一点的。

__index和**__newindex**

如下先创建一个带Metatable

-- 声明一个正常的关系变量
lo_table = {} 

-- 声明空元表变量
lo_meta_table = {}

-- 为关系变量t设置元表变量
setmetatable(lo_table, lo_meta_table) 

-- 获取一个关系变量的元表变量
getmetatable(lo_table)

setmetatable接收了两个参数,这两个参数都是表,lo_meta_table 变成了lo_table的 元表变量。后面对lo_meta_table 的操作,会影响到lo_table,元表lo_meta_table 可以有哪些操作呢?

最常见的是 __index和**__newindex**。

__index和**__newindex** 在表元素被访问和创建新元素的时候会被调用:

lo_table = setmetatable({}, {

  __index = function(lo_table, key)

    if key == "foo" then
      return 0
    else
      return table[key]
    end
  end
  ,

  __newindex = function(t, key, value)

	rawset(t, key, value)

  end
})

lo_table.x = 2

print(lo_table.x)
print(lo_table.foo)

这也就回答了上面的问题,表中的元素在被访问和创建的时候会调用元表中的**__index__newindex**。通过控制这两个函数,就能跟踪这个过程。

同样的在**__index**中也可以设置函数方法。

-- 创建元表变量
lo_meta_table = {
    action = function ( param )
        -- body
        if(param == "学习") then
            print("阿猫学编程")
        else
            print("python")
        end
    end
}

-- 设置该元表变量作为关系变量的
lo_table = setmetatable({}, { __index = lo_meta_table })

-- 打印lo_table变量的动作 阿猫学编程
print(lo_table.action("学习"))

-- 打印lo_table变量的动作 python
print(lo_table.action("编程"))

如上创建了一个方法action,在调用lo_table时,相当于拥有了一个action的方法。

__call

__index和**__newindex相类似的方法还有__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)

实现了**__call函数以后,在进行构造result的时会调用__call**方法。这时返回的不是一个表而是一个数值。

__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)
运算符

利用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])

__add 函数遍历了所有的数组,并把每个数组的元素加上2。当然这个函数可以定义为所需要的功能。

和__index 、__newindex 不同,__mul 的值只能是函数。与__mul类似的键有:

  • __add (+)
  • __sub (-)
  • __div (/)
  • __mod (%)
  • __unm 取负
  • __concat (…)
  • __eq (==)
  • __lt (<)
  • __le (<=)
创建向量Vector类

通过使用Metatables,使得表变得更加的灵活,他能够做的事情更多了,实现一些复杂点的类也轻松了许多。这里创建一个向量类。

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 })

这里使用了两种方式实现Vector类的创建,一种是Vector.new(x, y),另外一种实现了Vector的__call方法。

在下面中实现向量的加法运算。

-- + 运算符
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和b,做a和b的和运算,并打印出:

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

print(a)
print(c)
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

go2coding

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值