如何在Delphi中正确注册Lua userdata?
2013-11-22 15:53:4
收藏:0
阅读:344
评论:1
我仍然对将 Delphi 的 userdata 注册到 Lua 中感到困惑。为了教我原理,我试图实现一个日期(时间)类型。
一开始,这个类型应该有三个可用于 Lua 的函数:
- 一个
new函数用于创建该类型的变量。 - 一个
getdate函数。 - 以及一个
setdate函数。
最终,这个小型的 Lua 脚本将能够工作:
DT = DateTime.new()
DT:setdate(1, 1, 2011)
day, month, year = DT:getdate()
print("Day: " .. day .. " Month: " .. month .." Year: " .. year)
我试图自己实现它(使用 Programming in Lua 书籍),但是我收到一个错误:第 2 行上说:_attempt to index global 'DT' (a userdata value)_。我可能在 userdata 注册方面做错了什么,但我很难找到错误。
我希望你能帮我找到它,这是我已经得到的:
Const
MetaPosDateTime = 'DateTime';
Type
tLuaDateTime = tDateTime;
pLuaDateTime = ^tLuaDateTime;
Function newdatetime(aState : pLua_State) : longint; cdecl;
Var
NewData : pLuaDateTime;
Begin
Result := 0;
NewData := lua_newuserdata(aState, SizeOf(tLuaDateTime));
NewData^ := now;
luaL_newmetatable(aState, MetaPosDateTime);
lua_setmetatable(aState, -2);
Result := 1;
End;
Function setdate(aState : pLua_State) : longint; cdecl;
Var
DT : pLuaDateTime;
ParamType : integer;
day, month, year : lua_Integer;
Begin
Result := 0;
DT := luaL_checkudata(aState, 1, MetaPosDateTime);
luaL_argcheck(aState, DT <> Nil, 1, 'DataTime expected');
ParamType := lua_type(aState, 2);
If (ParamType = LUA_TTABLE) Then
Begin
{ GetData from Table }
End
Else
Begin // param order must be: day, month, year
day := luaL_checkinteger(aState, 2);
month := luaL_checkinteger(aState, 3);
year := luaL_checkinteger(aState, 4);
End;
DT^:= EncodeDate(year, month, day);
End;
Function getdate(aState : pLua_State) : longint; cdecl;
Var
DT : pLuaDateTime;
Day, Month, Year : Word;
Begin
DT := luaL_checkudata(aState, 1, MetaPosDateTime);
luaL_argcheck(aState, DT <> Nil, 1, 'DataTime expected');
DecodeDate(DT^, Year, Month, Day);
lua_pushinteger(aState, Day);
lua_pushinteger(aState, Month);
lua_pushinteger(aState, Year);
End;
Procedure RegisterDateTime(aState : pLua_State; aName: string);
Var
Funcs : packed Array[0..3] of luaL_reg;
Begin
Funcs[0].name := 'new';
Funcs[0].func := newdatetime;
Funcs[1].name := 'setdate';
Funcs[1].func := setdate;
Funcs[2].name := 'getdate';
Funcs[2].func := getdate;
Funcs[3].name := Nil;
Funcs[3].func := Nil;
luaL_register(aState, PAnsiChar(aName), Funcs[0]);
End;
因为我不确定 luaL_register 函数(它只能通过创建一个必须使用 require 调用的库来工作吗?),我还尝试用以下代码替换 RegisterDateTime 函数:
Type
tLuaFuncDef = Record
FuncName : string;
Func : Lua_CFunction;
End;
tLuaFuncList = Array of tLuaFuncDef;
Procedure RegisterLuaObject(aState : pLua_State; aObjectName: string; aFuncList: tLuaFuncList);
Var
i : Integer;
Begin
If (aObjectName = '') Or (High(aFuncList) < 0) Then
Exit;
lua_newtable(aState);
For i := Low(aFuncList) To High(aFuncList) Do
If Assigned(aFuncList[i].Func) And Not (aFuncList[i].FuncName = '') Then
Begin
lua_pushcfunction(aState, aFuncList[i].Func);
lua_setfield(aState, -2, pAnsiChar(aFuncList[i].FuncName));
End;
lua_SetGlobal(aState, pAnsiChar(aObjectName));
End;
Procedure RegisterDateTime(aState : pLua_State, aName: string);
Var
FuncList : tLuaFuncList;
Begin
SetLength(FuncList, 3);
FuncList[0].FuncName := 'new';
FuncList[0].Func := newdatetime;
FuncList[1].FuncName := 'setdate';
FuncList[1].Func := setdate;
FuncList[2].FuncName := 'getdate';
FuncList[2].Func := getdate;
RegisterLuaObject(aState, aName, FuncList);
End;
不幸的是,在 RegisterDateTime 的两个版本中,效果(errormessage :))都是相同的。它们在我的 Delphi 程序中直接调用,在脚本启动之前(我通过在 "RegisterDateTime" 和 "newdatetime" 中设置断点来确保这一点)。这两个函数按此顺序被调用,因此我的错误一定在这两个函数中的一个中。我几乎确定这只是一个简单的错误,但是我太瞎了,看不到它。 :(
点赞
评论区的留言会收到邮件通知哦~
推荐文章
- Lua 虚拟机加密load(string.dump(function)) 后执行失败问题如何解决
- 我想创建一个 Nginx 规则,禁止访问
- 如何将两个不同的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 代码?

今天我按下了这个项目的大重置按钮,完全重新开始了我的LuaDateTime类型的实现,今天我把它弄正确了。现在我想把我的解决方案发布为示例,供其他遇到同样问题的人参考。
昨天我最大的错误是忘记设置元表的
__index字段。Lua userdata的工作Delphi实现如下所示:Uses LuaLib, LauXLib, SysUtils; Type tLuaDateTime = tDateTime; pLuaDateTime = ^tLuaDateTime; Const PosMetaTaleLuaDateTime = 'metatables.LuaDateTime'; PosLuaDateTime = 'datetime'; Function checkLuaDateTime(L : Plua_State) : pLuaDateTime; // 如果第一个(self)参数不是metatables.LuaDateTime类型,将引发错误 Begin Result := luaL_checkudata(L, 1, PosMetaTaleLuaDateTime); End; Function newLuaDateTime(L : pLua_State) : LongInt; cdecl; Var a : pLuaDateTime; Begin a := lua_newuserdata(L, SizeOf(tLuaDateTime)); // 获取UserType的Mem a^ := now; // 初始化值 lua_getfield(L, LUA_REGISTRYINDEX, PosMetaTaleLuaDateTime); lua_setmetatable(L, -2); Result := 1; End; Function setLuaDateTime(L : pLua_State) : LongInt; cdecl; Var a : pLuaDateTime; day, month, year : Integer; Begin a := checkLuaDateTime(L); // 获取day、month和year参数 day := luaL_checkint(L, 2); month := luaL_checkint(L, 3); year := luaL_checkint(L, 4); // 检查参数值 luaL_argcheck(L, (day >= 1) and (day < 32), 2, 'day out of range'); luaL_argcheck(L, (month >= 1) and (month < 13), 3, 'month out of range'); a^ := EncodeDate(year, month, day); Result := 0; End; Function getLuaDateTime(L : pLua_State) : LongInt; cdecl; Var a : pLuaDateTime; day, month, year : Word; Begin a := checkLuaDateTime(L); DecodeDate(a^, year, month, day); // 推送函数的3个结果 lua_pushinteger(L, day); lua_pushinteger(L, month); lua_pushinteger(L, year); Result := 3; End; Function LuaDateTime2string(L : pLua_State) : LongInt; cdecl; Var a : pLuaDateTime; Begin a := checkLuaDateTime(L); lua_pushstring(L, pAnsiChar(FormatDateTime('c', a^))); Result := 1; End; Const LuaDateTimeLib_f : packed Array[0..1] of luaL_reg = // 正常函数(没有self) ( (name: 'new'; func: newLuaDateTime), (name: Nil; func: Nil) ); LuaDateTimeLib_m : packed Array[0..3] of luaL_reg = // 类的方法(需要self) ( (name: '__tostring'; func: LuaDateTime2string), (name: 'set'; func: setLuaDateTime), (name: 'get'; func: getLuaDateTime), (name: Nil; func: Nil) ); Function luaopen_LuaDateTime(L : pLua_State) : LongInt; cdecl; Begin luaL_newmetatable(L, PosMetaTaleLuaDateTime); // 元表.__index = 元表 lua_pushvalue(L, -1); lua_setfield(L, -2, '__index'); luaL_register(L, Nil, LuaDateTimeLib_m[0]); luaL_register(L,PosLuaDateTime, LuaDateTimeLib_f[0]); Result := 1; End;你必须从Delphi调用
luaopen_LuaDateTime来在Lua状态中注册类型。完成后,你可以运行这样的Lua脚本:dt = datetime.new() day, month, year = dt:get() print ("Day: " .. day .. " Month: " .. month .. " Year: " .. year) dt:set(1, 2, 1903) day, month, year = dt:get() print ("Day: " .. day .. " Month: " .. month .. " Year: " .. year)我希望对他人有所帮助。