D/Dlang: Lua 接口,有什么方法可以强制用户无法访问中间对象?

D/Dlang: Lua interface, any way to force users to have no access to intermediate objects?

状态:有点解决了。按照答案中的建议将 Lua.Ref(接近于 LuaD LuaObject)转换为 struct 已经解决了与释放引用相关的大多数问题,我改回了类似的机制 Lua D 使用。最后详细介绍一下。


在我的一个项目中,我正在使用 Lua 界面。我主要借鉴了 LuaD 的想法。 LuaD 中的机制使用 lua_ref & lua_unref 能够移动 D space 中的 lua table/function 引用,但这会导致严重的问题因为无法保证对析构函数的调用及其顺序。 LuaD 通常至少在程序退出时出现段错误。

因为LuaD好像已经不再维护了,所以我决定自己写一个接口来满足我的目的。我的 Lua 界面 class 在这里:https://github.com/mkoskim/games/blob/master/engine/util/lua.d

用法示例可在此处找到: https://github.com/mkoskim/games/blob/master/demo/luasketch/luademo.d

如果您需要,示例中使用的 Lua 脚本位于此处: https://github.com/mkoskim/games/blob/master/demo/luasketch/data/test.lua

界面是这样的:


关闭一切正常,除了这个机制有令人讨厌的quirk/bug,我不知道如何解决它。如果您不调用这些 "final" 方法中的任何一个,Top 将留下 table 和堆栈的键:

lua["math"]["abs"].call(-1); // Works. Final method (call) called.
lua["math"]["abs"];          // table ref & key left to stack :(

我确定的是,使用 Top() 析构函数不起作用,因为当对象不再被引用时它不会立即被调用。

注意:如果在对象作为右值访问时调用某种运算符,我可以用运算符重载替换 call()、set() 和 get() 方法。

问题:

  1. 有什么方法可以防止用户写这样的表达式(获取Top对象而不调用任何"final"方法)?我真的不希望用户写例如luafunc = lua["math"]["abs"] 然后稍后尝试调用它,因为它根本不起作用。并非没有开始玩 lua_ref & lua_unref 并开始与 LuaD 遇到的相同问题作斗争。

  2. 有没有什么opAccess运算符重载,也就是重载object作为右值时会发生什么?也就是说,表达式 "a = b" -> "a.opAssign(b.opAccess)"? opCast 不起作用,它只能通过显式转换调用。


还有其他建议吗?我内心觉得我正在从错误的方向寻找解决方案。我觉得问题出在元编程领域:我正在尝试 "scope" 表达式级别的东西,我觉得这不是 classes 和对象的 suitable。

到目前为止,我已经尝试在界面用户端保留 LuaD 外观,但我认为如果我可以将界面更改为如下所示,我可以让它正常工作:

lua.call(["math", "abs"], 1);          // call lua.math.abs(2)
lua.get(["table", "x", "y", "z"], 2);  // lua table.x.y.z = 2
...

从语法上讲,这将确保对通过索引获取的 lua 对象的引用最终用于表达式中的某些内容,并且堆栈将被清理。


更新: 如前所述,将 Lua.Ref 更改为 struct 解决了与取消引用相关的问题,我再次使用类似于 LuaD 的引用机制。我个人觉得这种机制也适合我正在使用的 LuaD 风格的语法,要使这种语法与其他机制一起正确工作可能是一个很大的挑战。我仍然愿意听听是否有人有想法让它发挥作用。

我草拟的替换引用的系统(解决对象持有的引用比 lua 沙盒寿命长的问题)可能需要不同类型的界面,类似于我在上面草拟的东西。

人们这样做时你也有问题

auto math_abs = lua["math"]["abs"];

math_abs.call(1);
math_abs.call(3);

这会加倍弹出。

使 Top 成为一个结构,其中包含它们所引用内容的堆栈索引。这样您就可以利用其已知的范围界定和破坏行为来发挥自己的优势。确保您也正确处理 this(this)

只有当值是实际的最高值时才在析构函数中弹出。您可以使用 LuaInterface 中的位集来跟踪正在使用的堆栈位置,如果您担心过度使用堆栈,可以使用 lua_replace 将值放入其中。