使用“."的困惑.在Lua中使用__index和命名空间表示 [英] Confusion of using "." notation with __index and namespace in Lua

查看:202
本文介绍了使用“."的困惑.在Lua中使用__index和命名空间表示的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我对使用."的以下两种语法感到困惑.

I am confused of the following two syntaxes using "."

  1. 据我了解,当表中不存在键但其元表中存在键时,会调用__index.那么,为什么列表表调用__index然后将其自身分配给list.__index?

  1. From what I understand, __index is called when a key doesn't exist in a table but exists in its metatable. So why does the list table call __index and then assign itself to list.__index?

list = {}
list.__index = list

setmetatable(list, { __call = function(_, ...)
local t = setmetatable({length = 0}, list)
  for _, v in ipairs{...} do t:push(v) end
  return t
end })

function list:push(t)
  if self.last then
    self.last._next = t
    t._prev = self.last
    self.last = t
  else
   self.first = t
   self.last = t
  end
  self.length = self.length + 1
end 
  .
  .
  .
local l = list({ 2 }, {3}, {4}, { 5 })

  • Window.mt是否仅创建一个表?为什么我们在这里需要Window = {}作为命名空间?

  • Does Window.mt simply create a table? Why do we need Window = {} as a namespace here?

    Window = {}  -- create a namespace    
    Window.mt = {}  -- create a metatable
    Window.prototype = {x=0, y=0, width=100, height=100, } 
    
    function Window.new (o)  
        setmetatable(o, Window.mt)
        return o
    end
    
    Window.mt.__index = function (table, key)
        return Window.prototype[key]
    end
    
    w = Window.new{x=10, y=20}
    print(w.width)    --> 100
    

  • 推荐答案

    那为什么列表表调用__index然后将其自身分配给list .__ index?

    列表表中的调用 __index在代码中都没有.但是,分配部分是通用的Lua习惯用法(又名hack),以节省一些内存.从概念上讲,涉及4种不同的表:

    So why does the list table call __index and then assign itself to list.__index?

    Nowhere in your code does the list table call __index. The assignment part however is a common Lua idiom (aka. hack) to save some memory. Conceptually there are 4 different kinds of tables involved:

    1. 列出对象(通过代码中的{length=0}创建的表)
    2. 一个元表(包含一个__index字段),当您尝试访问对象中不存在的字段时,它会修改列表对象的行为
    3. list类,其中包含列表对象的所有方法(如push方法),并且还用作列表对象的构造函数
    4. 用于list类的元表(包含__call字段),因此您可以像调用函数一样调用list

    1. list objects (the tables created via {length=0} in your code)
    2. a metatable (containing an __index field) that modifies the behavior of list objects when you try to access non-existing fields in the object
    3. the list class, which holds all the methods for list objects (like the push method), and also serves as a constructor for list objects
    4. a metatable (containing a __call field) for the list class, so that you can call the list table as if it were a function

    由于元表字段总是以两个下划线(__)开头,而普通方法通常不是这样,因此可以将元表字段和普通方法并排放置在单个表中,而不会发生冲突.这就是这里发生的事情. list类表还用作列表对象的元表.因此,使用此技巧,您可以节省通常需要用于单独的元表的内存(x86-64 Linux上Lua 5.2的大小(以字节为单位)显示在表标题栏中的方括号内,btw.):

    As metatable fields always start with two underscores (__), and normal methods usually don't, you can put metatable fields and normal methods side by side into a single table without conflict. And this is what happened here. The list class table also serves as metatable for list objects. So using this trick you can save the memory you would normally need for the separate metatable (the size in bytes for Lua 5.2 on an x86-64 Linux is shown in square brackets in the table title bars, btw.):

    否,{}创建一个表.但是,此新表保存在Window表中的键"mt"下,可能是为了使该Window类"的用户直接访问用于窗口对象的元表.仅给出您显示的代码,这并不是绝对必要的,您可以使用局部变量代替.

    No, {} creates a table. However, this new table is saved under key "mt" in the Window table, probably to give users of this Window "class" direct access to the metatable that is used for window objects. Given only the code you showed this is not strictly necessary, and you could have used a local variable instead.

    原则上,您可以分别存储Window.mtWindow.newWindow.prototype,但是如果您有多个像"c17>"这样的类",那将变得很麻烦.这样,您可以避免名称冲突,并且使用Window"class"看起来更好.

    In principle, you could store Window.mt, Window.new, and Window.prototype separately, but that would get cumbersome if you have multiple "classes" like Window. This way you can avoid name clashes, and using the Window "class" looks nicer.

    另一个原因可能是require只能从模块定义中返回单个值,如果要从模块中导出多个值(例如newmtprototype),则可以需要一个表将它们包装在一起(或使用全局变量,但这被认为是不好的样式).

    Another reason might be that require can only return a single value from a module definition, and if you want to export multiple values (like new, mt, and prototype) from a module, you need a table to wrap them together (or use global variables, but that is considered bad style).

    这篇关于使用“."的困惑.在Lua中使用__index和命名空间表示的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

    查看全文
    登录 关闭
    扫码关注1秒登录
    发送“验证码”获取 | 15天全站免登陆