Lua中混合类型的相等运算符
2015-9-17 18:59:39
收藏:0
阅读:67
评论:2
在《Lua 编程(第二版)》的第 13.2 章中指出:
与算术元方法不同,关系元方法不支持混合类型。
与此同时,
Lua 只有在被比较的两个对象共享此元方法时才调用相等元方法。
因此,我在 C 中实现我的库,并希望能够支持以下行为:
a = A()
b = B()
a == b
提供以下内容:
static const struct luaL_Reg mylib_A[] =
{
{ "__eq", my_equal }
, <more stuff>
, { NULL, NULL }
};
和
static const struct luaL_Reg mylib_B[] =
{
{ "__eq", my_equal }
, <more stuff>
, { NULL, NULL }
};
但是这似乎不起作用,有没有解决办法?
注:my_equal 可以处理任何参数中类型为 A 和类型为 B 的 userdata。
更新: 注册元表:
luaL_newmetatable(lua, "B");
lua_pushvalue(lua, -1);
lua_setfield(lua, -2, "__index");
luaL_register(lua, NULL, mylib_B);
luaL_newmetatable(lua, "A");
lua_pushvalue(lua, -1);
lua_setfield(lua, -2, "__index");
luaL_register(lua, NULL, mylib_A);
luaL_register(lua, "mylib", mylib); -- 其中 mylib 是一堆静态函数
应用程序代码:
require 'mylib'
a = mylib.new_A()
b = mylib.new_B()
a == b -- __eq 没有被调用
点赞
用户1212010
对于其他遇到相同问题的人:
这是我让 Lua 意识到 my_equal 在两种情况下都是相同函数的唯一方式,从而正确地从 getcomphandler 中返回操作符的。以任何其他方式注册它(包括单独的 luaL_Reg)都不起作用,因为 my_equal 在 luaL_register 时保存在不同的闭包下,我通过仅创建一次闭包来避免这种情况。
// 我们将它复制到下面以确保 Lua 知道它是同一个函数
lua_pushcfunction(lua, my_equal);
luaL_newmetatable(lua, "B");
// 为了清晰起见去掉了 __index
luaL_register(lua, NULL, mylib_B);
// 现在我们单独注册 __eq
lua_pushstring(lua, "__eq");
lua_pushvalue(lua, -3); // 将 my_equal 复制到上面
lua_settable(lua, -3); // 将其注册到 B 的元表下
lua_pop(lua, 1);
luaL_newmetatable(lua, "A");
// 为了清晰起见去掉了 __index
luaL_register(lua, NULL, mylib_A);
lua_pushstring(lua, "__eq");
lua_pushvalue(lua, -3); // 将 my_equal 复制到上面
lua_settable(lua, -3); // 将其注册到 A 的元表下
luaL_register(lua, "mylib", mylib); // 其中 mylib 是一堆静态函数
2015-09-17 21:59:16
评论区的留言会收到邮件通知哦~
推荐文章
- 如何将两个不同的lua文件合成一个 东西有点长 大佬请耐心看完 我是小白研究几天了都没搞定
- 如何在roblox studio中1:1导入真实世界的地形?
- 求解,lua_resume的第二次调用继续执行协程问题。
- 【上海普陀区】内向猫网络招募【Skynet游戏框架Lua后端程序员】
- SF爱好求教:如何用lua实现游戏内调用数据库函数实现账号密码注册?
- Lua实现网站后台开发
- LUA错误显式返回,社区常见的规约是怎么样的
- lua5.3下载库失败
- 请问如何实现文本框内容和某个网页搜索框内容连接,并把网页输出来的结果反馈到另外一个文本框上
- lua lanes多线程使用
- 一个kv数据库
- openresty 有没有比较轻量的 docker 镜像
- 想问一下,有大佬用过luacurl吗
- 在Lua执行过程中使用Load函数出现问题
- 为什么 neovim 里没有显示一些特殊字符?
- Lua比较两个表的值(不考虑键的顺序)
- 有个lua简单的项目,外包,有意者加微信 liuheng600456详谈,最好在成都
- 如何在 Visual Studio 2022 中运行 Lua 代码?
- addEventListener 返回 nil Lua
- Lua中获取用户配置主目录的跨平台方法
__eq元方法应该放在你的元表中,而不是放在__index表中。在Lua中:
function my_equal(x,y) return x.value == y.value end A = {} A.__eq = my_equal function new_A(value) local a = { value = value } return setmetatable(a, A) end B = {} B.__eq = my_equal function new_B(value) local b = { value = value } return setmetatable(b, B) end a = new_A() b = new_B() print(a == b) -- __eq is called, result is true a.value = 5 print(a == b) -- __eq is called, result is false你所做的是:
myLib_A = {} myLib_A.__eq = my_equal A = {} A.__index = myLib_A请注意,
__eq不在A的元表中,它在一个完全不同的表中,你恰好在不同的、不相关的元方法(__index)中使用它。Lua在尝试解决运算符“==”的相等性时将不会在那里查找。Lua手册对此进行了详细解释:
function getcomphandler (op1, op2, event) if type(op1) ~= type(op2) then return nil end local mm1 = metatable(op1)[event] local mm2 = metatable(op2)[event] if mm1 == mm2 then return mm1 else return nil end endfunction eq_event (op1, op2) if type(op1) ~= type(op2) then -- different types? return false -- different objects end if op1 == op2 then -- primitive equal? return true -- objects are equal end -- try metamethod local h = getcomphandler(op1, op2, "__eq") if h then return (h(op1, op2)) else return false end end因此,当 Lua 遇到
result = a == b时,它将执行以下操作(此操作是在 C 中完成的,在此处使用 Lua 作为伪代码):-- 操作数的类型相同吗?在我们的情况下,它们都是表: if type(a) ~= type(b) then return false end -- 操作数是同一个对象吗?这个比较是在C代码中完成的,所以它不会重新调用相等操作符。 if a ~= b then return false end -- 操作数是否有相同的“__eq”元方法? local mm1 = getmetatable(a).__eq local mm2 = getmetatable(b).__eq if mm1 ~= mm2 then return false end -- 为左操作数调用“__eq”元方法(与右相同,没有什么区别) return mm1(a,b)您可以看到,这里没有任何路径可以解决
a.__eq,这会通过您的__index元方法解析为myLib_A。