1、本文将继续讲解在Lua Code中调用注册的C函数.偶在学习本文知识点时,由于知识点的遗漏,在这个上面浪费了大量时间和精力。一直都没有没明白,Lua 通过面向对象的方式是如果调用注册的C函数。在Programming In Lua一书,有对这个方面的讲解。但是当时看书,就是不理解。因为在前面的章节中,有一个重要的知识点被遗漏。在Lua 元方法中,有两个特别重要的.__index 和__newindex被我遗漏。这两个元方法特别重要,对于定义和拓展Lua的机制,基本依靠这两个。
2、本文首先由Lua Code中对__index 和__nexindex 的讲解引入,来对通过Lua Code 面向对象调用注册的C函数。
2.1 在Lua Code中讲解metatable中__index和__newindex两个重要的元方法
2.2 注册C模块
2.3 通过Lua Code面向对象调用注册的C函数。
3、本文作为在Lua 中实现面向对象编程和在Lua中绑定C++对象的一个铺垫。在Lua的演化中,作者并没有把面向对象特点加入的Lua的语言中,但是,一个语言的发展深入当时环境的影响,Lua在发展时,由用户的原因,被迫满足在Lua中提供面向对象的需求。在Lua中实现面向对象只要依靠Table和metatable两个机制,来实现面向对象的形式。
4、本文不是详细讲解Lua 编写语言的知识点,但是会总结关键知识点。对于Lua本身的学习,主要Programming In Lua 和Lua Reference Manual 足以.
5.1 下面LuaCode将讲解元方法和Lua Code中实现面试对象调用:
object ={} methodTab ={} setmetatable(object, methodTab) methodTab.__tostring=function() print("object tostring...") return "object" end methodTab.__call=function() print("object call...") end methodTab["method"]=function() print("object method...") return "object method" end object() --对Table进行函数调用,对于__call 元函数 tostring(object) print(object) <span style="color:#ff0000;">methodTab.__index =methodTab --__index元方法表示对Object Table的进行定义.当调用Object["method"]获取Object指定键操作时,如果Object中不存在指定键,</span>
<span style="color:#ff0000;">则在查询Object是否存在metatable,如果存在metatable则在metatable中查询指定键元素。</span> local m =object["method"] print(m) m()
<pre name="code" class="plain">object["method"]()
由于在忽悠__index 和__nexindex知识点,在后来的学习中,总是理解不清楚,浪费了大量的时间。在此特别罗列出知识点,希望能够减少读者在错误的道路上浪费的时间。
5.2 下面例子代码来自于Programming In Lua的章节中。来讲述注册C模块和通过Lua面向对象调用注册的C函数。在Lua中面向对象调用,实际是Lua作者不想把面向对象机制引入Lua语言本身,导致语言复杂性,而引入一种语法糖来实现面向对象调用。在Lua作者的文章中多次提及Lua语言本身不提供面向对象机制,但是提供对面向对象的支持。
后面的文章会继续设计Lua的面向对象东东,包括对Lua作者面向对象观点的翻译。
extern "C" { #include <lua.h> #include <lualib.h> #include <lauxlib.h> } #include <stdio.h> #define CnExampleStr "example" //在C语言中的结构体,绑定到Lua语言中 typedef struct { int Val; int Open; } ExampleType, * ExamplePtrType; static ExamplePtrType LclExamplePtrGet(lua_State *L,int StkPos) { ExamplePtrType ExamplePtr = (ExamplePtrType)luaL_checkudata(L, StkPos, CnExampleStr); if (! ExamplePtr->Open) luaL_error(L, "attempt to use a closed " CnExampleStr); return ExamplePtr; } static int LclExampleStr(lua_State *L) { ExamplePtrType ExamplePtr = (ExamplePtrType)luaL_checkudata(L, 1, CnExampleStr); if (ExamplePtr->Open) lua_pushfstring(L, CnExampleStr " (%d)", ExamplePtr->Val); else lua_pushfstring(L, CnExampleStr " (%d, closed)", ExamplePtr->Val); return 1; } //获取c结构体数据 static int LclExampleGet(lua_State *L) { ExamplePtrType ExamplePtr = LclExamplePtrGet(L, 1); lua_pushnumber(L, ExamplePtr->Val); printf("Retrieving value of " CnExampleStr " (%d)\n", ExamplePtr->Val); return 1; } //设置c结构体数据 static int LclExampleSet(lua_State *L) { ExamplePtrType ExamplePtr = LclExamplePtrGet(L, 1); int Val = luaL_checkint(L, 2); printf("Setting value of " CnExampleStr " from %d to %d\n", ExamplePtr->Val, Val); lua_pushnumber(L, ExamplePtr->Val); ExamplePtr->Val = Val; return 1; } //关闭结构体 static int LclExampleClose(lua_State *L) { ExamplePtrType ExamplePtr = LclExamplePtrGet(L, 1); printf("Closing " CnExampleStr " (%d) explicitly\n", ExamplePtr->Val); ExamplePtr->Open = 0; return 0; } //通过Lua Code构造C语言结构体 static int LclExampleOpen(lua_State *L) { //接受LuaCode传递参数 int Val = luaL_checkint(L, 1); //申请由lua GC管理下的内存 ExamplePtrType ExamplePtr =(ExamplePtrType)lua_newuserdata(L, sizeof(ExampleType)); printf("Opening " CnExampleStr " (%d)\n", Val); //设置数据 ExamplePtr->Val = Val; ExamplePtr->Open = 1; ////在注册表中查询注册的C函数 luaL_getmetatable(L, CnExampleStr); //设置userdata的CnExampleStr的metatable lua_setmetatable(L, -2); return 1; } void luaopen_register(lua_State *L) { static const luaL_reg regMethod[] = { {"open", LclExampleOpen}, {"close", LclExampleClose}, {"get", LclExampleGet}, {"set", LclExampleSet}, {"tostring", LclExampleStr}, {NULL, NULL} }; //创建一个metatable用于标识userdata唯一性 luaL_newmetatable(L, CnExampleStr); luaL_register(L,"ud_example",regMethod); } int main(int argc, char **argv) { /* initialize Lua */ lua_State* L = lua_open(); luaL_openlibs(L); //luaopen_ud_example(L); luaopen_register(L); luaL_dofile(L, "sample_6.lua"); /* cleanup Lua */ lua_close(L); return 1; }
sample_6.lua 测试代码如下:
print("sample_6.lua") local ud1 =ud_example.open(1) print(ud1) print(ud_example.tostring(ud1)) local a =ud_example.get(ud1) print("a:"..a) local b =ud_example.set(ud1,2) print("b="..b)
整个注册模块和Lua Code调用演示模块已经完成。至于Lua Code如何管理C/C++对象的生命周期,会在后面陆续介绍。在这个例子中没有涉及到Lua GC垃圾收集器。
到目前为止只要记住,Lua为了提高用户自定义数据类型,提供了userdata数据类型。userdata数据类型的生命周期由Lua GC管理。当userdata管理的C/C++对象时,当GC把userdata当做垃圾收集时,会调用__gc userdata的元方法。假如,C/C++对象生命周期由Lua GC管理,那么此时是释放C/C++对象的唯一机会。
本文中涉及到环境和userdata的如何使用?可以参考Lua Reference Manual .在本系列文章中,将会不断的讲解userdata的由来和使用方式方法。
本来本文应该完成第三部分,通过Lua Code面向对象语法糖调用注册的C函数,无奈,这内容比较多,涉及知识点较多。和老婆约好了,11点去同事家完,不想本文草草了事情,所以第三部以及涉及的知识点,将在下一张详细讲述。