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點去同僚家完,不想本文草草了事情,是以第三部以及涉及的知識點,将在下一張詳細講述。