zoukankan      html  css  js  c++  java
  • 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://www.cnblogs.com/daxiaxiaohao/p/4651767.html

  • 相关阅读:
    基于maven使用IDEA创建多模块项目
    开发时用于文件前说明
    nginx配置ThinkPHP配置
    spring原理机制
    将spring源码导入到eclipse中
    【调试】Core Dump是什么?Linux下如何正确永久开启?
    【最详细最完整】在Linux 下如何打包免安装的QT程序?
    Linux 下qt 程序打包发布(使用linuxdelpoyqt ,shell 脚本)
    Ubuntu 守护进程
    【Qt】QLabel之动态阴影边框
  • 原文地址:https://www.cnblogs.com/zhenlong/p/4862874.html
Copyright © 2011-2022 走看看