精华内容
下载资源
问答
  • lua 元表的补充说明

    2018-06-04 20:56:22
    前面讲过lua元表的作用(详见lua元表),尤其对__index有重点讲解。在研究skynet源码时发现了__index新的用法,记录一下。 我们已经知道__index的作用是表查找不到字段时的索引,索引我们见到的__index都是另一个表...

    1 __index

    前面讲过lua元表的作用(详见lua元表),尤其对__index有重点讲解。在研究skynet源码时发现了__index新的用法,记录一下。

     我们已经知道__index的作用是表查找不到字段时的索引,索引我们见到的__index都是另一个表,实际上__index也可以是一个函数。函数在字段查找不到时触发。

    例如下面的代码:

    local function fun(t, field)
        local a = 200   
        t[field] = 105
        return a
    end
    
    local t = setmetatable({}, {__index = fun})
    print(t.k)   --200
    print(t.k)   --105,此时不再触发元表

    我们访问t.key时,由于没有这个字段,就会触发fun函数。其中传入函数的参数是该表本身,已经要访问的字段名key。注意函数的返回值就是t.key的值200,而不是重新返回t。

    我们注意到函数中也给t[filed]赋值了,所以再次访问t.key时为105,而不是200了。

    如果我们先赋值t.key = 159,那么打印t.key是多少呢?

    仍然还是159,因为t.key已经有值,不会再次触发元表了。

    我们可以根据上面的特性,给表的字段一个初始值,再次访问时又设置一个值。

    2 __gc

    __gc是对象声明周期结束时调用的函数,例如:

    setmetatable(tab, {__gc = function() ... end})

    当tab生命周期结束时会调用function。这种用法一般用于回收资源,例如socket关闭时的收尾工作等等。

    3 __mode

    __mode是弱表引用,如果一个table1,里面还有一个table2对象,那么即使将这个table2赋值为nil,它依然不会被垃圾回收因为table1还存有着对这个对象的引用,显然这样的引用是没有必要的。通过以下代码,你可以认识这一点。

    local arr = {}
    local temp = {}
    arr[1] = temp
    temp = nil
    
    print(arr[1])      --还是会打印arr[1]引用的那个表

    如果想arr不再引用那个表,则可以对arr设置弱表引用:

    local arr = {}
    local temp = {}
    arr[1] = temp
    temp = nil
    
    setmetatable(arr, {__mode = 'v'})
    
    collectgarbage()   --强制垃圾回收
    print(arr[1])      --此时为nil

    更多详细信息请参考:

    https://blog.csdn.net/jiumengdz/article/details/88427895

    https://blog.csdn.net/qq_35080184/article/details/83420528

    展开全文
  • LUA元表和类的简单例子

    千次阅读 2013-11-25 17:16:07
    学习lua有一段时间了,今天终于学会了怎么使用元表,还有用lua表模拟类,综合实例讲解,用lua元表模拟C++模板和类
    学习lua有一段时间了,今天终于学会了怎么使用元表,还有用lua表模拟类,综合实例讲解,用lua元表模拟C++模板和类
    
    下面是我工作实践操作的实例,测试通过,非常容易扩展其他元方法
    -- 源码
    local SET = {} -- 模拟C++类
    local mt = {} -- 元模板
    --// 建立新表
    function SET.new(tb)
    	local set = {}
    	setmetatable(set,mt)
    	for k,v in ipairs(tb) do
    		set[k] = v
    	--	print("init v:"..v)
    	end
    	return set
    end
    --// 元方法
    function SET.add(a,b)
    	local res = SET.new{0,0,0,0}
    	for k,v in pairs(res) do
    		res[k] = a[k] + b[k]
    	end
    	return res
    end
    --// 测试打印
    function SET.print(s)
    	for k,v in pairs(s) do
    		print("s["..k.."]:"..v)
    	end
    end
    -- 设置元方法
    mt.__add = SET.add
    
    --// 测试
    s1 = SET.new{10,20,30,50}--{10,20,30,50} --
    s2 = SET.new{6,7,8,9}--{6,7,8,9} --
    setmetatable(s1,mt)
    setmetatable(s2,mt)
    --//print(getmetatable(s1))
    --//print(getmetatable(s2))
    local s3 = {0,0,0,0}
    s3 = s1 + s2
    print("print"..#s1..","..#s2)
    SET.print(s3)


    
    
    
    
    
    
    
    
    
    
    
    
    
    
    
    
    
    
    
    
    
    
    
    
    
    
    
    
    
    
    
    
    
    
    
    
    
    
    
    
    
    
    展开全文
  • Lua-元表的使用

    2020-02-25 20:46:58
    元表使用部分讲解 本文主要用于自己学习内容的总结,有错误欢迎指出,谢谢。 元表的作用 元表的目的是用来定义table 和 userdata 的表 --两种常用的方法 setmetatable(table,setmetatable) --对指定 table 设置元表...

    元表使用部分讲解

    本文主要用于自己学习内容的总结,有错误欢迎指出,谢谢。


    元表的作用

    元表的目的是用来定义table 和 userdata 的表 (大概像一个使用说明)

    --两种常用的方法
    setmetatable(table,setmetatable) --对指定 table 设置元表(metatable),如果元表(metatable)中存在 
    __metatable 键值,setmetatable 会失败。
    getmetatable(table) --返回对象的元表(metatable)

    举个列子:

    local t1 ={1}
    local t2 ={2}
    local t3 = t1 + t2

    运行上面的代码就会报错,因为我们执行了两个table 相加的操作,但是Lua并不知道如何将两个table相加。此时我们就需要重新定义table的运算规则,有点像c语言中重载struct的操作符


    算术类的元方法

    假设我们使用table作为集合,并且使用一些函数用来计算集合的交集和并集。为了保持命名空间的整齐,将这些函数写入到名为Set的table中。

    Set = {}
    function Set.new(l) --根据参数列表l的值创建一个新的集合
     local set ={}
     for _,v in ipairs(l) do
       set[v] = true 
     end
     return set
    end
    
    function Set.union(a,b)--取并集
     local res = Set.new{}
     for k in pairs(a) do res[k] = true end
     for k in pairs(b) do res[k] = true end
     return res
    end
    
    function Set.intersection(a,b)--去交集
     local res = Set.new{}
     for k in pairs(a) do res[k] = b[k] end
     return res
    end
    --打印集合函数,方便检测
    function Set.tostring(set)
     local l = {}
     for e in pairs(set) do 
      l[#l+1] = e
     end
     return "{"..table.concat(l.",").."}"
    end
    
    function Set.print(s)
     print(Set.tostring(s))
    end
    

    现在我们使用 + 表示计算两个集合的交集,那么此时我就需要让这两个集合共用一个元表,并且要在元表中定义如何执行加法的操作。

    local mt = {} --集合的元表

    此时我们需要修改Set.new函数。该函数用于创建集合,在新版本中加入一行,将mt设置为当前创建table的元表:

    function Set.new(l)
     local set = {}
     setmetatable(set,mt)
     for _,v in ipairs(l) do set[v] = true end
     return set
    end
    --此时我们使用Set.new所创建的集合都共用了一个元表(mt)
    s1 = Set.new(10,20,30,50)
    s2 = Set.new(40,60)
    --此时我们需要把元方法加入到元表中,__add 这个字段描述将加法加入到这个元表中。
    --+表示两个集合的并集
    mt.__add = Set.union
    s3 = s1 + s2
    Set.print(s3) --->(10,20,30,40,50,60)
    --类似用*表示两个集合相交,只需把 __mul 加入到元表中
    mt.__mul = Set.intersection
    s3 = (s1+s2)*s1
    Set.print(s3) -->(10,20,30,50)
    

    算术元方法

    函数 描述
    __add 运算符 +
    __sub 运算符 -
    __mul 运算符 *
    __div 运算符 /
    __pow 运算符 ^(幂函数)
    __mod 运算符 %
    __unm 运算符 -(取反)
    __concat 运算符 …(连接)

    关系类的元方法

    和算术类基本相同。但是有三种是关系运算符是不存在的(~=,>,>=)。Lua中会把 ~= 转换为 not (a==b),a>b 转化为b<a,将a>=b 转化为了b<=a。以上面集合为例,在集合操作中,通常<=表示集合间的包含关系:a<=b通常意味着a是b的一个子集。

    关系元方法

    函数 描述
    __eq 运算符 ==
    __lt 运算符 <
    __le 运算符 <=

    我们来具体实现一下代码:

    mt.__le = function (a,b)
      for k in pairs(a) do 
        if not b[k] then return false end
      end
      return true
    end
    
    mt.__lt = funtion (a,b)
      return a<=b and not (b<=a)
    end
    
    mt.__eq = function (a,b)
      return a<=b and b<=a
    end
        
    s1 = Set.new{2,4}
    s2 = Set.new{2,4,10}
    print(s1 <= s2)     -->true
    print(s1 < s2)      -->true
    print(s1 >= s1)     -->true
    print(s1 > s2)      -->false
    print(s1 = s2 * s1) -->true
        

    算术类和关系类不同

    关系类的元方法不能缓和类型。如果尝试用一个字符串比较数字类型的话,Lua就会报错。


    库定义的元方法

    各种程序库在元表中定义他们自己的字段是很普遍的方法。到目前所有的元方法只针对于Lua的核心,也就是一个虚拟机。它会检测一个操作中的值是否有元表,这些元表中是否定义了关于此操作的元方法。从某一方面说,元表也是一种常规的table,任何人,任何函数都可以使用它。
    函数tostring就是一个经典案例,tostring可以将各种类型的值表示为简单的文本格式:

    print({})  --> table:

    函数print总是调用tostring来格式化输出。当格式化任意值时,tostring会检查该值是否有一个__tostring的元方法,如果有这个元方法,tostring就用该值作为参数来调用这个元方法。接下来由这个元方法来完成工作,其返回结果也是tostring的结果。接下来我们来使用上面写到的代码:

    mt.__tostring = Set.tostring
    s1 = Set.new{10,2,5}
    print(s1)   --> {2,5,10}

    call函数可以让table当作函数来访问:

    function Set.call(...)
      for _,v in ipairs {...} do
        print(v)
      end
    end
    mt.__call = Set.call
    s1 = Set.new{}
    s1(1,2,3,4)  -->1,2,3,4
    函数 描述
    __tostring 转化为字符串类型
    __call 将table当作函数

    table 访问的元方法

    Lua的表本质其实是个类似HashMap的东西,其元素是很多的Key-Value对。如果尝试访问了一个表中并不存在的元素时,就会返回一个nil值,这样说不全对,实际上当访问table中不存在的字段时,会使解释器去查找一个__index的元方法。如果这个元方法不存在,才会返回这个nil值。而且__index这个元方法和前面不同,__index即可以是个函数,也可以是一个table。
    __index作为函数方法实现:

    function Set.index(t,key)  --t表示自己,key表索引
      return "not_find_"..key
    end
    mt.__index = Set.index
    s1 = {1,2,3}
    print(s1.key) -->nil
    s2 = Set.new{1,2,3}
    print(s2.key)  --> not_find_key

    __index作为table实现:

    mt.__index = {key = "not_find_key"}
    s1 = Set.new{1,2,3}
    print(s1.key) --> not_find_key
    print(s1.key2)  --> nil

    __index作为table 和函数时效果相似,但也不一样,如上面的例子。因为我们的key2 没有定义,所以Lua再查找时,就返回了nil。


    除了__index的元方法,table中还存在一种__newindex的元方法。两者相似但又不同,前者用于查询,而后者则用于table的更新。如果__newindex元方法是一个table,解释器就会在这个table中赋值,而不是原来的table。
    作为函数时:

    mt.__newindex = function(t,index,value)
      print("index is"..index)
      print("value is"..value)
    end
    s1 = {key = "it is key"}
    setmetatable = (s1,mt)
    print(s1) --> it is key --表中存在索引key,直接输出
    s1.newKey = 10
    print(s1.newKey) -->index is newKey  --表中并不存在newKey索引,所以调用元方法。
    -->value is 10
    -->nil
    

    作为table时:

    local newTable = {}
    mt.__newindex = newTable
    t={}
    setmetatable(t,mt)
    print(t.key,newTable.key) --> nil nil
    t.key = "it is key"
    print(t.key,newTable.key) --> nil it is key
    
    函数 描述
    __index 访问一个索引
    __newindex 给索引赋值

    展开全文
  • 这篇文章主要介绍了Lua中的元表与元方法学习总结,本文讲解了算术类的元方法、__tostring元方法等内容,需要的朋友可以参考下 前言 元表对应的英文是metatable,元方法是metamethod。我们都知道,...

    Lua中的元表与元方法学习总结

    作者:果冻想 字体:[增加 减小] 类型:转载 时间:2014-09-29 我要评论

    这篇文章主要介绍了Lua中的元表与元方法学习总结,本文讲解了算术类的元方法、__tostring元方法等内容,需要的朋友可以参考下

    前言

    元表对应的英文是metatable,元方法是metamethod。我们都知道,在C++中,两个类是无法直接相加的,但是,如果你重载了“+”符号,就可以进行类的加法运算。在Lua中也有这个道理,两个table类型的变量,你是无法直接进行“+”操作的,如果你定义了一个指定的函数,就可以进行了。那这篇博文就是主要讲的如何定义这个指定的函数,这个指定的函数是什么?希望对学习Lua的朋友有帮助。

    Lua是怎么做的?

    通常,Lua中的每个值都有一套预定义的操作集合,比如数字是可以相加的,字符串是可以连接的,但是对于两个table类型,则不能直接进行“+”操作。这需要我们进行一些操作。在Lua中有一个元表,也就是上面说的metatable,我们可以通过元表来修改一个值得行为,使其在面对一个非预定义的操作时执行一个指定的操作。比如,现在有两个table类型的变量a和b,我们可以通过metatable定义如何计算表达式a+b,具体的在Lua中是按照以下步骤进行的:

    先判断a和b两者之一是否有元表;
    检查该元表中是否有一个叫__add的字段;
    如果找到了该字段,就调用该字段对应的值,这个值对应的是一个metamethod;(Lua中方法是可以放在一个字段中的,还记得???忘了点这里
    调用__add对应的metamethod计算a和b的值。
    上述四个步骤就是计算table类型变量a+b的过程。在Lua中,每个值都有一个元表,table和userdata类型的每个变量都可以有各自独立的元表,而其他类型的值则共享其类型所属的单一元表。

    告别metatable小白

    现在就说说最基本的metatable内容。Lua在创建新的table时不会创建元表,比如以下代码就可以演示:

    复制代码代码如下:

    local t = {1, 2}
    print(getmetatable(t))     -- nil

    我们是使用getmetatable来获取一个table或userdata类型变量的元表,当创建新的table变量时,使用getmetatable去获得元表,将返回nil;同理,我们也可以使用setmetatable去设置一个table或userdata类型变量的元表,例如以下代码:
    复制代码代码如下:

    local t = {}
    print(getmetatable(t))     -->nil
     
    local t1 = {}
    setmetatable(t, t1)
    assert(getmetatable(t) == t1)

    任何table都可以作为任何值得元表,而一组相关的table有可以共享一个通用的元表,此元表描述了它们共同的行为。一个table甚至可以作为它自己的元表,用于描述其特有的行为。总之,任何搭配形式都是合法的。

    在Lua代码中,只能设置table的元表。若要设置其它类型的值得元表,则必须通过C代码来完成。还存在一个特例,对于字符串,标准的字符串程序库为所有的字符串都设置了一个元表,而其它类型在默认情况下都没有元表。查看两句代码的打印值,就可以看出来:

    复制代码代码如下:

    print(getmetatable("Hello World"))
    print(getmetatable(10))

    在table中,我可以重新定义的元方法有以下几个:

    复制代码代码如下:

    __add(a, b) --加法
    __sub(a, b) --减法
    __mul(a, b) --乘法
    __div(a, b) --除法
    __mod(a, b) --取模
    __pow(a, b) --乘幂
    __unm(a) --相反数
    __concat(a, b) --连接
    __len(a) --长度
    __eq(a, b) --相等
    __lt(a, b) --小于
    __le(a, b) --小于等于
    __index(a, b) --索引查询
    __newindex(a, b, c) --索引更新(PS:不懂的话,后面会有讲)
    __call(a, ...) --执行方法调用
    __tostring(a) --字符串输出
    __metatable --保护元表

    接下来就介绍介绍如果去重新定义这些方法。

    算术类的元方法

    现在我使用完整的实例代码来详细的说明算术类元方法的使用。我准备定义一些对集合的操作方法,所有的方法都放入Set这个table中,至于为什么table中可以存放函数,可以参考《Lua中的函数》这篇文章。下面的代码是我模拟的一个集合的操作:

    复制代码代码如下:

    Set = {}
    local mt = {} -- 集合的元表
     
    -- 根据参数列表中的值创建一个新的集合
    function Set.new(l)
        local set = {}
         setmetatable(set, mt)
        for _, v in pairs(l) do set[v] = true end
         return set
    end
     
    -- 并集操作
    function Set.union(a, b)
        local retSet = Set.new{} -- 此处相当于Set.new({})
        for v in pairs(a) do retSet[v] = true end
        for v in pairs(b) do retSet[v] = true end
        return retSet
    end
     
    -- 交集操作
    function Set.intersection(a, b)
        local retSet = Set.new{}
        for v in pairs(a) do retSet[v] = b[v] end
        return retSet
    end
     
    -- 打印集合的操作
    function Set.toString(set)
         local tb = {}
         for e in pairs(set) do
              tb[#tb + 1] = e
         end
         return "{" .. table.concat(tb, ", ") .. "}"
    end
     
    function Set.print(s)
         print(Set.toString(s))
    end

    现在,我定义“+”来计算两个集合的并集,那么就需要让所有用于表示集合的table共享一个元表,并且在该元表中定义如何执行一个加法操作。首先创建一个常规的table,准备用作集合的元表,然后修改Set.new函数,在每次创建集合的时候,都为新的集合设置一个元表。代码如下:

    复制代码代码如下:

    Set = {}
    local mt = {} -- 集合的元表
     
    -- 根据参数列表中的值创建一个新的集合
    function Set.new(l)
        local set = {}
         setmetatable(set, mt)
        for _, v in pairs(l) do set[v] = true end
         return set
    end

    在此之后,所有由Set.new创建的集合都具有一个相同的元表,例如:

    复制代码代码如下:

    local set1 = Set.new({10, 20, 30})
    local set2 = Set.new({1, 2})
    print(getmetatable(set1))
    print(getmetatable(set2))
    assert(getmetatable(set1) == getmetatable(set2))

    最后,我们需要把元方法加入元表中,代码如下:

    复制代码代码如下:

    mt.__add = Set.union

    这以后,只要我们使用“+”符号求两个集合的并集,它就会自动的调用Set.union函数,并将两个操作数作为参数传入。比如以下代码:
    复制代码代码如下:

    local set1 = Set.new({10, 20, 30})
    local set2 = Set.new({1, 2})
    local set3 = set1 + set2
    Set.print(set3)

    在上面列举的那些可以重定义的元方法都可以使用上面的方法进行重定义。现在就出现了一个新的问题,set1和set2都有元表,那我们要用谁的元表啊?虽然我们这里的示例代码使用的都是一个元表,但是实际coding中,会遇到我这里说的问题,对于这种问题,Lua是按照以下步骤进行解决的:

    1.对于二元操作符,如果第一个操作数有元表,并且元表中有所需要的字段定义,比如我们这里的__add元方法定义,那么Lua就以这个字段为元方法,而与第二个值无关;

    2.对于二元操作符,如果第一个操作数有元表,但是元表中没有所需要的字段定义,比如我们这里的__add元方法定义,那么Lua就去查找第二个操作数的元表;

    3.如果两个操作数都没有元表,或者都没有对应的元方法定义,Lua就引发一个错误。
    以上就是Lua处理这个问题的规则,那么我们在实际编程中该如何做呢?比如set3 = set1 + 8这样的代码,就会打印出以下的错误提示:

    复制代码代码如下:

    lua: test.lua:16: bad argument #1 to 'pairs' (table expected, got number)

    但是,我们在实际编码中,可以按照以下方法,弹出我们定义的错误消息,代码如下:

    复制代码代码如下:

    function Set.union(a, b)
         if getmetatable(a) ~= mt or getmetatable(b) ~= mt then
              error("metatable error.")
         end
     
        local retSet = Set.new{} -- 此处相当于Set.new({})
        for v in pairs(a) do retSet[v] = true end
        for v in pairs(b) do retSet[v] = true end
        return retSet
    end

    当两个操作数的元表不是同一个元表时,就表示二者进行并集操作时就会出现问题,那么我们就可以打印出我们需要的错误消息。

    上面总结了算术类的元方法的定义,关系类的元方法和算术类的元方法的定义是类似的,这里不做累述。

    __tostring元方法

    写过Java或者C#的人都知道,Object类中都有一个tostring的方法,程序员可以重写该方法,以实现自己的需求。在Lua中,也是这样的,当我们直接print(a)(a是一个table)时,是不可以的。那怎么办,这个时候,我们就需要自己重新定义__tostring元方法,让print可以格式化打印出table类型的数据。

    函数print总是调用tostring来进行格式化输出,当格式化任意值时,tostring会检查该值是否有一个__tostring的元方法,如果有这个元方法,tostring就用该值作为参数来调用这个元方法,剩下实际的格式化操作就由__tostring元方法引用的函数去完成,该函数最终返回一个格式化完成的字符串。例如以下代码:

    复制代码代码如下:

    mt.__tostring = Set.toString

    如何保护我们的“奶酪”——元表

    我们会发现,使用getmetatable就可以很轻易的得到元表,使用setmetatable就可以很容易的修改元表,那这样做的风险是不是太大了,那么如何保护我们的元表不被篡改呢?

    在Lua中,函数setmetatable和getmetatable函数会用到元表中的一个字段,用于保护元表,该字段是__metatable。当我们想要保护集合的元表,是用户既不能看也不能修改集合的元表,那么就需要使用__metatable字段了;当设置了该字段时,getmetatable就会返回这个字段的值,而setmetatable则会引发一个错误;如以下演示代码:

    复制代码代码如下:

    function Set.new(l)
        local set = {}
         setmetatable(set, mt)
        for _, v in pairs(l) do set[v] = true end
         mt.__metatable = "You cannot get the metatable" -- 设置完我的元表以后,不让其他人再设置
         return set
    end
     
    local tb = Set.new({1, 2})
    print(tb)
     
    print(getmetatable(tb))
    setmetatable(tb, {})

    上述代码就会打印以下内容:

    复制代码代码如下:

    {1, 2}
    You cannot get the metatable
    lua: test.lua:56: cannot change a protected metatable

    __index元方法

    是否还记得当我们访问一个table中不存在的字段时,会返回什么值?默认情况下,当我们访问一个table中不存在的字段时,得到的结果是nil。但是这种状况很容易被改变;Lua是按照以下的步骤决定是返回nil还是其它值得:

    1.当访问一个table的字段时,如果table有这个字段,则直接返回对应的值;
    2.当table没有这个字段,则会促使解释器去查找一个叫__index的元方法,接下来就就会调用对应的元方法,返回元方法返回的值;
    3.如果没有这个元方法,那么就返回nil结果。

    下面通过一个实际的例子来说明__index的使用。假设要创建一些描述窗口,每个table中都必须描述一些窗口参数,例如颜色,位置和大小等,这些参数都是有默认值得,因此,我们在创建窗口对象时可以指定那些不同于默认值得参数。

    复制代码代码如下:

    Windows = {} -- 创建一个命名空间
     
    -- 创建默认值表
    Windows.default = {x = 0, y = 0, width = 100, height = 100, color = {r = 255, g = 255, b = 255}}
     
    Windows.mt = {} -- 创建元表
     
    -- 声明构造函数
    function Windows.new(o)
         setmetatable(o, Windows.mt)
         return o
    end
     
    -- 定义__index元方法
    Windows.mt.__index = function (table, key)
         return Windows.default[key]
    end
     
    local win = Windows.new({x = 10, y = 10})
    print(win.x)               -- >10 访问自身已经拥有的值
    print(win.width)          -- >100 访问default表中的值
    print(win.color.r)          -- >255 访问default表中的值

    根据上面代码的输出,结合上面说的那三步,我们再来看看,print(win.x)时,由于win变量本身就拥有x字段,所以就直接打印了其自身拥有的字段的值;print(win.width),由于win变量本身没有width字段,那么就去查找是否拥有元表,元表中是否有__index对应的元方法,由于存在__index元方法,返回了default表中的width字段的值,print(win.color.r)也是同样的道理。

    在实际编程中,__index元方法不必一定是一个函数,它还可以是一个table。当它是一个函数时,Lua以table和不存在key作为参数来调用该函数,这就和上面的代码一样;当它是一个table时,Lua就以相同的方式来重新访问这个table,所以上面的代码也可以是这样的:

    复制代码代码如下:

    -- 定义__index元方法
    Windows.mt.__index = Windows.default

    __newindex元方法

    __newindex元方法与__index类似,__newindex用于更新table中的数据,而__index用于查询table中的数据。当对一个table中不存在的索引赋值时,在Lua中是按照以下步骤进行的:

    1.Lua解释器先判断这个table是否有元表;
    2.如果有了元表,就查找元表中是否有__newindex元方法;如果没有元表,就直接添加这个索引,然后对应的赋值;
    3.如果有这个__newindex元方法,Lua解释器就执行它,而不是执行赋值;
    4.如果这个__newindex对应的不是一个函数,而是一个table时,Lua解释器就在这个table中执行赋值,而不是对原来的table。

    那么这里就出现了一个问题,看以下代码:

    复制代码代码如下:

    local tb1 = {}
    local tb2 = {}
     
    tb1.__newindex = tb2
    tb2.__newindex = tb1
     
    setmetatable(tb1, tb2)
    setmetatable(tb2, tb1)
     
    tb1.x = 10

    发现什么问题了么?是不是循环了,在Lua解释器中,对这个问题,就会弹出错误消息,错误消息如下:

    复制代码代码如下:

    loop in settable

    丢掉那该死的元表

    有的时候,我们就不想从__index对应的元方法中查询值,我们也不想更新table时,也不想执行__newindex对应的方法,或者__newindex对应的table。那怎么办?在Lua中,当我们查询table中的值,或者更新table中的值时,不想理那该死的元表,我们可以使用rawget函数,调用rawget(tb, i)就是对table tb进行了一次“原始的(raw)”访问,也就是一次不考虑元表的简单访问;你可能会想,一次原始的访问,没有访问__index对应的元方法,可能有性能的提升,其实一次原始访问并不会加速代码执行的速度。对于__newindex元方法,可以调用rawset(t, k, v)函数,它可以不涉及任何元方法而直接设置table t中与key k相关联的value v。

    总结

    这篇博文具体的总结了Lua中的元表和元方法,可以说Lua中的元表和元方法是很多内容的基础,所以我在这里总结的很详细,并结合了很多代码。如果你有幸看到了这篇文章,希望你也花点时间认真的读一读,想要理解Lua,玩转Lua,当然了,不能只是会一些语法,掌握元表和元方法是必不可少的。最后,也希望这篇文章对大家有用。下一篇博文,我会结合__index和__newindex说一些实例代码。

    展开全文
  • 主要介绍了Lua教程(九):元表与元方法详解,本文讲解了算术类的元方法、关系类的元方法、库定义的元方法、table访问的元方法等内容,需要的朋友可以参考下
  • 【Lua进阶系列】之Lua元方法案例+字段 大家好,我是Lampard~~ 欢迎来到Lua进阶系列的博客 前文再续,书接上一回。今天和大家讲解一下lua中的元方法 __index字段 说起lua那么就不得不提其元表,lua...
  • 这篇文章主要介绍了Lua中的元表与元方法学习总结,本文讲解了算术类的元方法、__tostring元方法等内容,需要的朋友可以参考下 前言 元表对应的英文是metatable,元方法是metamethod。我们都知道,在C++中,两...
  • Lua学习与交流——元表的基础

    千次阅读 2014-02-24 17:01:57
    关于Lua元表,建议大家先读读Programming in Lua这本书里的讲解,我这里也对书里所讲的内容作一些总结。 一、什么是元表?  元表(meta table)定义了一组方法(元方法),来改变一个表的行为。我把元表作为一个表的...
  • 元表在项目中的运用,其中就包括元方法这点。元方法是指__index和__newIndex,下面我总结下,更详细的例子讲解可以参考《lua程序设计 第2版》的第13章内容。长h短说,简言之有关table的查询就找__index,有关table的...
  • 这篇文章主要介绍了Lua中的元表(metatable)、元方法(metamethod)详解,本文对它做了详细讲解,并给出实例来说明,需要的朋友可以参考下终于到了在实际中经常要用到的内容了——元表与元方法。 在第一次看见这两...
  • lua的学习过程当中,元表metatable的概念及用法是常见的障碍之一 元表,在其它lua杂谈等都提到过,是一种描述lua数据的属性以及行为的表。虽然官方给了set、account等例子详细讲解了metatable,但总还是缺乏些提炼...
  • Lua中__index 和__newindex 讲解

    千次阅读 2015-11-16 14:53:27
    这篇博文将通过几个简单的实例演示,巩固对__index和__newindex的理解,同时加深对Lua中元表和元方法的理解,如果对Lua元表和元方法还不是很熟悉的话,请参考这篇文章:《Lua中的元表与元方法》。 具有默认值的...
  • 今天和大家讲解一下lua中的__newindex方法 (一)什么是_newindex 如果说__index字段是在访问中不存在的值(get)是执行的操作的话 那么__nexindex字段则是在对表中不存在的值进行赋值(set)时候执行的...
  • Lua面向对象编程

    2019-11-29 14:44:31
    因此,要想在lua上像其他高级语言一样使用面向对象的设计方法有以下两种选择:一种是使用原生的元表(metatable)来模拟面向对象设计,另外一种则是使用第三方框架LuaScriptoCore来实现。下面将逐一讲解这两种方式的...
  • Lua热更新技术中级篇

    2019-12-14 20:29:47
    内容包含lua可变参数、闭包、模块、函数尾调用、字符串模式匹配、字符串不变性原理、矩阵、链表、元表详解与应用、协同的生命周期与生产消费者问题、lua文件各种读写操作、lua执行外部代码与错误异常处理垃圾收集...
  • lua面向对象详解(2)

    2013-12-01 23:24:49
    从这里开始,将讲解lua元表和元方法。 二、元表与元方法 我们知道c++ 中不能随便将两个对象相加,除非程序用户自己定义+操作符,指定两个对象相加时需要做的操作。lua也是一样,不能将两个table进行算术操作,...
  • Lua语法知识点 模拟类

    2019-06-26 16:19:09
    先贴一下代码 具体讲解等我哪天闲了再去别人那里扒一扒 local aaa = {} aaa.__index = aaa local AAA = setmetatable({}, aaa) if nil ~= AAA then _G.AAA = AAA end 1.定义一个变量 是一个空 2.这个变量的...
  • 本次案例介绍抢红包的场景,模拟20万红包,分为400个小红包,每个红包500,有1000千人并发同时抢夺,并讲解会出现超发和保证如何数据一致性问题,在高并发场景下还需要保证性能的问题。 在这里,首先查看红包库存...
  • Laravel 5.1 LTS 速查 Symfony2 Cookbook 中文版(版本 2.7.0 LTS) Symfony2中文文档 (未译完) YiiBook几本Yii框架的在线教程 深入理解 Yii 2.0 Yii 框架中文文檔 简单易懂的PHP魔法 swoole文档及入门教程 ...

空空如也

空空如也

1 2
收藏数 21
精华内容 8
关键字:

lua元表讲解