如何实现面向对象?
熟悉Lua的同学都知道!在Lua内部已经实现了面向对象的基本机制(table), 同时也为宿主语言(在这里是C语言)提供了一套接口来实现自定义数据结构(userdata)。在此,我们可以简单的利用metatable与__index的访问机制,为userdata实现一套简单的面向对象的访问方式。
stu.c
#include <lua.h>
#include <lualib.h>
#include <lauxlib.h>
typedef struct _Student
{
const char * strName ; // 学生姓名
int strNum ; // 学号
int iSex ; // 学生性别
int iAge ; // 学生年龄
}Student;
int lnew(lua_State* L){
Student *stu = lua_newuserdata(L,sizeof(Student));
if(NULL == stu){
return 0;
}
luaL_setmetatable(L,"stu");
return 1;
}
int lset(lua_State* L){
Student *stu = luaL_checkudata(L,1,"stu");
stu->strName = luaL_checkstring(L,2);
stu->strNum = luaL_checkinteger(L,3);
stu->iSex = luaL_checkinteger(L,4);
stu->iAge = luaL_checkinteger(L,5);
return 0;
}
int lget(lua_State* L){
Student *stu = luaL_checkudata(L,1,"stu");
lua_pushstring(L,stu->strName);
lua_pushinteger(L,stu->strNum);
lua_pushinteger(L,stu->iSex);
lua_pushinteger(L,stu->iAge);
return 4;
}
const luaL_Reg mylib[] = {
{"new",lnew},
{"set",lset},
{"get",lget},
{NULL,NULL}
};
LUA_API int luaopen_stu(lua_State* L){
luaL_newmetatable(L,"stu");
lua_pushstring (L,"__index");
lua_pushvalue(L,-2);
lua_rawset(L,-3);
luaL_setfuncs(L,mylib,0);
luaL_newlib(L,mylib);
return 1;
}
main.lua
local stu = require "stu"
local stu = stu.new()
print(stu)
stu:set("Candy",1024,1,26)
local name,id,sex,age = stu:get()
print(name,id,sex,age)
运行结果:
[root@localhost ~]# cc -o stu.so stu.c -Wall -O2 -fPIC -shared
[root@localhost ~]# lua main.lua
stu: 0x19380d8
Candy 1024 1 26
[root@localhost ~]#
运行结果很简单。现在,我们简要分析一下具体实现步奏。
首先我们在注册表创建了一个metatable,并且起名”stu”。然后为这个元表添加一个__index元方法,然后将自身作为键值查找域。最后使用setfuncs为元表注入方法。
上述步奏等效于lua中如下操作:
local meta = {1,2,3}
local t = setmetatable({},{__index=meta})
print(t[1])
这里需要注意的是:
- full-userdata的生命周期是由Lua来管理的。</td>
- 如果由Lua gc回收了userdata的使用空间,C语言还引用原地址将会引起段错误。
- 所以如果需要完全使用C API来管理 userdata是生命周期,请使用light userdata。