隐藏Lua元表并仅公开对象';s属性

隐藏Lua元表并仅公开对象';s属性,lua,lua-table,metatable,lua-5.2,Lua,Lua Table,Metatable,Lua 5.2,如何创建只公开其属性而不公开其方法的Lua对象?例如: localobj={ attr1=1, attr2=2, 打印=函数(…) 打印(“obj打印:,…) 完,, } 产生: >对于k,v成对(obj)打印(k,v)结束 属性1 属性2 2 打印功能:0x7ffe1240a310 另外,在Lua中,OOP是否可以不使用冒号语法?我不需要继承、多态性,只需要封装和隐私。我从上述问题开始,在追查兔子洞之后,我惊讶于示例数量有限,缺乏各种元方法的示例(即\uuuu ipairs,\uu pai

如何创建只公开其属性而不公开其方法的Lua对象?例如:

localobj={
attr1=1,
attr2=2,
打印=函数(…)
打印(“obj打印:,…)
完,,
}
产生:

>对于k,v成对(obj)打印(k,v)结束
属性1
属性2 2
打印功能:0x7ffe1240a310

另外,在Lua中,OOP是否可以不使用冒号语法?我不需要继承、多态性,只需要封装和隐私。

我从上述问题开始,在追查兔子洞之后,我惊讶于示例数量有限,缺乏各种元方法的示例(即
\uuuu ipairs
\uu pairs
\uu len
),关于这个主题的LUA5.2资源有多少

Lua可以进行OOP,但在我看来,OOP的规定方式是对语言和社区的一种伤害(即,以支持多态性、多重继承等的方式)。对于大多数问题,很少有理由使用Lua的OOP特性。它也不一定意味着有一个岔路口(例如,为了支持多态性,没有任何东西说你必须使用冒号语法-你可以将文献中描述的技术折叠到基于闭包的OOP方法中)

我知道在Lua中有很多方法可以实现OOP,但是对象属性和对象方法的语法不同(例如,
obj.attr1
vs
obj:getAttr()
vs
obj.method()
vs
obj:method()
vs
obj:method())。我想要一个单一的、统一的API来进行内部和外部通信。为此,这是一个极好的开始,但这是一个不完整的例子,我希望用这个答案来弥补


以下示例代码:

  • 模拟类的命名空间
    MyObject={}
    并将对象构造函数另存为
    MyObject.new()
  • 隐藏对象内部工作的所有详细信息,以便对象的用户只看到纯表(请参见
    setmetatable()
    \uu metatable
  • 使用闭包进行信息隐藏(请参见和)
  • 防止修改对象(请参见
    \uuu newindex
  • 允许截取方法(请参见
    \u索引
  • 用于获取所有函数和属性的列表(请参见
    \uu index
    中的“key”属性)
  • 看起来、行动、行走和说话都像普通的Lua表(请参见
    \uuuu pairs
    \uuu len
    \uu ipairs
  • 在需要时看起来像字符串(请参见
    \uuuu-tostring
  • 与Lua 5.2配合使用
下面是构建新的
MyObject
的代码(这可能是一个独立的函数,它不需要存储在
MyObject
表中-一旦创建了
obj
,就绝对没有任何东西会将其绑定到
MyObject.new()
,这只是为了熟悉和不合时宜):

MyObject={}
MyObject.new=函数(名称)
本地objectName=name
--我们想要公开的属性表
本地属性={
attr1=123,
}
--对象的方法表(注意“end”上的逗号)
本地方法={
method1=函数()
打印(“\tmethod1”)
完,,
打印=函数(…)
打印(“MyObject.print():”,…)
完,,
--支持不太理想的冒号语法
printOOP=函数(自,…)
打印(“MyObject:printOOP():”,…)
完,,
}
--向对象添加方法的另一种样式(我更喜欢前者)
--因为复制/粘贴函数()更容易)
函数方法addAttr(k,v)
属性[k]=v
打印(“\taddAttr:添加新属性:“..k..=\”..v..\”)
结束
--用于自定义new()返回的表的行为的元表
本地机器翻译={
--在attrs表中查找不存在的键。为“键”索引创建一个特例
__指数=函数(t,k)
v=rawget(属性,k)
如果v那么
打印(“信息:已成功找到项\“…k….”的值”)
返回v
结束
--“键”是方法和属性的联合
如果k=='keys',则
局部ks={}
对于k,v在next中,attrs,nil do
ks[k]=“属性”
结束
对于next,methods中的k,v,nil do
ks[k]=“func”
结束
返回ks
其他的
打印(“警告:查找不存在的密钥\..k..\”)
结束
完,,
__ipairs=函数()
局部函数iter(a,i)
i=i+1
局部v=a[i]
如果v那么
返回i,v
结束
结束
返回iter,属性,0
完,,
__len=函数(t)
本地计数=0
对于成对(属性)do count=count+1 end
返回计数
完,,
__元表={},
__newindex=函数(t,k,v)
如果rawget(attrs,k)那么
打印(“信息:已成功设置“.k..=\”…v..\”)
原始集(属性,k,v)
其他的
打印(“错误:忽略新的键/值对”。.k..“=\”…v..“\”)
结束
完,,
__pairs=函数(t,k,v)返回next,attrs,nil end,
__tostring=函数(t)返回objectName..“[”。tostring(#t)“]”结束,
}
可设置元(方法,mt)
返回方法
结束
现在是用法:

——创建对象
local obj=MyObject.new(“我的对象的名称”)
打印(“迭代对象中的所有索引:”)
对于k,v成对(obj)打印(“”,k,v)结束
打印()
打印(“由于空的_图元表:”,obj有一个可见的空图元表)
对于成对的k,v(getmetatable(obj))执行打印(“”,k,v)结束
打印()
打印访问
-- create Point class
Point = {}
Point.__index = Point
function Point:report() print(self.x, self.y) end

-- create instance of Point
pt = setmetatable({x=10, y=20}, Point)

-- call method
pt:report() --> 10 20

-- iterate attributes
for k,v in pairs(pt) do print(k,v) end --> x 10 y 20
function Point(x, y)
    local self = { x=x, y=y}
    function pt.report() print(self.x, self.y) end
    return self
end

pt = Point(10,20)
pt.report() --> 10 20

for k,v in pairs(pt) do print(k,v) end --> x 10 y 20 report function: 7772112
function nextattribute(t, k)
   local v
   repeat
       k,v = next(t, k)
       if type(v) ~= 'function' then return k,v end
   until k == nil
end

function attributes (t)
  return nextattribute, t, nil
end

for k,v in attributes(pt) do print(k,v) end --> x 10 y 20