快速掌握Lua 5.3 —— userdata (2)
来源:互联网 发布:棋牌室收银软件 编辑:程序博客网 时间:2024/06/05 10:45
Q:如何使用”userdata”的”metamethods”?
A:我们继续来修改上一节中的例子,这次我们的目标是使用面向对象的方式调用”userdata”的方法。这个目标既可以在Lua中实现,也可以在C库中实现,我们先来看一个比较简单的方式,在Lua中实现。”mylib.c”中代码无需更改,只需要修改”a.lua”中的代码,
local array = require "mylib"--[[ 这里创建一个大小为1的数组,仅仅是为了获取其"metatable"。 虽然Lua代码无法更改"userdata"的"metatable", 但是获取"metatable"以及修改"metamethods"是不受影响的。 因为所有通过"array.new"创建的数组, 均使用存储在"registry"中的同一个"metatable"。 所以这里修改了此"metatable"的"metamethods", 下面所创建的数组也就拥有了这些"metamethods"。]]local metaarray = getmetatable(array.new(1))metaarray.__index = metaarraymetaarray.set = array.setmetaarray.get = array.getmetaarray.size = array.sizea = array.new(1000)print(a) --> userdata: 0x240f268print(a:size()) --> 1000for i = 1, 1000 do a:set(i, 1 / i)endprint(a:get(10)) --> 0.1
在Lua中实现的方式虽然方便,但在实际应用中却并不推荐。因为提供C库的意义就在于让使用者方便的调用提供的函数,而基于这种实现方式下,难道要在发布的C库的”Readme.txt”中说明在使用时需要增加的代码,以及暴露自己C库中定义的函数名称?
所以为了避免这些问题,我们接下来将在C库中实现”userdata”的”metamethods”。
/* 将"l"中所有的函数注册到从栈顶开始"nup"个"upvalues"下的"table"中, * 被注册的函数共享"nup"个"upvalues"。 * "nup"个"upvalues"在函数执行完成后会被出栈。 */void luaL_setfuncs(lua_State *L, const luaL_Reg *l, int nup);
“mylib.c”文件中:
#include <stdio.h>#include <string.h>#include <lua.h>#include <lauxlib.h>#include <lualib.h>typedef struct NumArray{ int size; double values[1];} NumArray;static NumArray *checkarray(lua_State *L){ void *ud = luaL_checkudata(L, 1, "LuaBook.array"); luaL_argcheck(L, ud != NULL, 1, "'array' expected"); return (NumArray *)ud;}static double *getelem(lua_State *L){ NumArray *a = checkarray(L); int index = luaL_checkinteger(L, 2); luaL_argcheck(L, 1 <= index && index <= a->size, 2, "index out of range"); return &a->values[index - 1];}static int newarray(lua_State *L){ int n = luaL_checkinteger(L, 1); size_t nbytes = sizeof(NumArray) + (n - 1)*sizeof(double); NumArray *a = (NumArray *)lua_newuserdata(L, nbytes); luaL_getmetatable(L, "LuaBook.array"); // 注意,这里使用的不是"luaL_setmetatable",两个函数的功能不同。 lua_setmetatable(L, -2); a->size = n; return 1;}static int setarray(lua_State *L){ double value = luaL_checknumber(L, 3); *getelem(L) = value; return 0;}static int getarray(lua_State *L){ lua_pushnumber(L, *getelem(L)); return 1;}static int getsize(lua_State *L){ NumArray *a = checkarray(L); lua_pushnumber(L, a->size); return 1;}static int array2string(lua_State *L){ NumArray *a = checkarray(L); lua_pushfstring(L, "array(%d)", a->size); return 1;}/* 现在C库中只需要向外部提供创建数组的方法, * 那些需要通过对象调用的方法都以"metamethods"的形式放在了"metatable"中。 */static const struct luaL_Reg arraylib_f[] = { {"new", newarray}, {NULL, NULL}};/* "metamethods"。 * 因为"userdata"根本就没有"keys",所以每当调用C库中未向外部提供的方法时, * 都会来寻找对应的"metamethods"。static const struct luaL_Reg arraylib_m[] = { // 将对象转换为字符串时,默认会调用的"metamethod"。 {"__tostring", array2string}, {"set", setarray}, {"get", getarray}, {"size", getsize}, {NULL, NULL}};extern int luaopen_mylib(lua_State* L){ luaL_newmetatable(L, "LuaBook.array"); // 新创建的"metatable"会入栈。 lua_pushstring(L, "__index"); lua_pushvalue(L, -2); // 复制一份"metatable"再次入栈。 lua_settable(L, -3); // "metatable.__index = metatable" // 将"metamethods"都存入"metatable"中。 luaL_setfuncs(L, arraylib_m, 0); luaL_newlib(L, arraylib_f); return 1;}
将”mylib.c”编译为动态连接库,
prompt> gcc mylib.c -fPIC -shared -o mylib.so -Wallprompt> lsmylib.c mylib.so a.lua
“a.lua”文件中:
local array = require "mylib"a = array.new(1000)--[[ 传递给"print"的参数会自动调用对象的"__tostring"方法, C库中提供了此"metamethod",所以这里不再打印"userdata: ***", 而是打印指定格式的信息。]]print(a) --> array(1000)print(a:size()) --> 1000for i = 1, 1000 do a:set(i, 1 / i)endprint(a:get(10)) --> 0.1
附加:
1、我们还可以使用常规数组的访问方式访问我们在C库中定义的数组,只需要将metaarray.__index
指向getarray
,metaarray.__newindex
指向setarray
。由于这种实现方式,metaarray.__index
只能指向单一的函数,getsize
和array2string
这类函数还是需要定义在luaL_newlib
接收的数组中。
在Lua中实现:
“mylib.c”文件中:
#include <stdio.h>#include <string.h>#include <lua.h>#include <lauxlib.h>#include <lualib.h>typedef struct NumArray{ int size; double values[1];} NumArray;static NumArray *checkarray(lua_State *L){ void *ud = luaL_checkudata(L, 1, "LuaBook.array"); luaL_argcheck(L, ud != NULL, 1, "'array' expected"); return (NumArray *)ud;}static double *getelem(lua_State *L){ NumArray *a = checkarray(L); int index = luaL_checkinteger(L, 2); luaL_argcheck(L, 1 <= index && index <= a->size, 2, "index out of range"); return &a->values[index - 1];}static int newarray(lua_State *L){ int n = luaL_checkinteger(L, 1); size_t nbytes = sizeof(NumArray) + (n - 1)*sizeof(double); NumArray *a = (NumArray *)lua_newuserdata(L, nbytes); luaL_getmetatable(L, "LuaBook.array"); // 注意,这里使用的不是"luaL_setmetatable",两个函数的功能不同。 lua_setmetatable(L, -2); a->size = n; return 1;}static int setarray(lua_State *L) { double value = luaL_checknumber(L, 3); *getelem(L) = value; return 0;}static int getarray(lua_State *L){ lua_pushnumber(L, *getelem(L)); return 1;}static int getsize(lua_State *L){ NumArray *a = checkarray(L); lua_pushnumber(L, a->size); return 1;}static int array2string(lua_State *L){ NumArray *a = checkarray(L); lua_pushfstring(L, "array(%d)", a->size); return 1;}static const struct luaL_Reg arraylib[] = { {"new", newarray}, {"size", getsize}, {"set", setarray}, {"get", getarray}, {"tostring", array2string}, {NULL, NULL}};extern int luaopen_mylib(lua_State* L){ luaL_newmetatable(L, "LuaBook.array"); luaL_newlib(L, arraylib); return 1;}
“a.lua”文件中:
local array = require "mylib"local metaarray = getmetatable(array.new(1))metaarray.__index = array.getmetaarray.__newindex = array.seta = array.new(1000)print(array.tostring(a)) --> array(1000)print(array.size(a)) --> 1000for i = 1, 1000 do a[i] = (1 / i)endprint(a[10]) --> 0.1
在C库中实现:
“mylib.c”文件中:
#include <stdio.h>#include <string.h>#include <lua.h>#include <lauxlib.h>#include <lualib.h>typedef struct NumArray{ int size; double values[1];} NumArray;static NumArray *checkarray(lua_State *L){ void *ud = luaL_checkudata(L, 1, "LuaBook.array"); luaL_argcheck(L, ud != NULL, 1, "'array' expected"); return (NumArray *)ud;}static double *getelem(lua_State *L){ NumArray *a = checkarray(L); int index = luaL_checkinteger(L, 2); luaL_argcheck(L, 1 <= index && index <= a->size, 2, "index out of range"); return &a->values[index - 1];}static int newarray(lua_State *L){ int n = luaL_checkinteger(L, 1); size_t nbytes = sizeof(NumArray) + (n - 1)*sizeof(double); NumArray *a = (NumArray *)lua_newuserdata(L, nbytes); luaL_getmetatable(L, "LuaBook.array"); lua_setmetatable(L, -2); a->size = n; return 1;}static int setarray(lua_State *L) { double value = luaL_checknumber(L, 3); *getelem(L) = value; return 0;}static int getarray(lua_State *L){ lua_pushnumber(L, *getelem(L)); return 1;}static int getsize(lua_State *L){ NumArray *a = checkarray(L); lua_pushnumber(L, a->size); return 1;}static int array2string(lua_State *L){ NumArray *a = checkarray(L); lua_pushfstring(L, "array(%d)", a->size); return 1;}static const struct luaL_Reg arraylib[] = { {"new", newarray}, {"size", getsize}, // 数组转换为字符串的函数不再作为"metamethod",而是显式的提供给外部。 {"tostring", array2string}, {NULL, NULL}};extern int luaopen_mylib(lua_State* L){ luaL_newmetatable(L, "LuaBook.array"); lua_pushstring(L, "__index"); lua_pushcfunction(L, getarray); lua_settable(L, -3); // metatable.__index = getarray lua_pushstring(L, "__newindex"); lua_pushcfunction(L, setarray); lua_settable(L, -3); // metatable.__newindex = setarray luaL_newlib(L, arraylib); return 1;}
“a.lua”文件中:
local array = require "mylib"a = array.new(1000)print(array.tostring(a)) --> array(1000)print(array.size(a)) --> 1000for i = 1, 1000 do a[i] = (1 / i) -- 常规数组访问方式。endprint(a[10]) --> 0.1 -- 常规数组访问方式。
0 0
- 快速掌握Lua 5.3 —— userdata (2)
- 快速掌握Lua 5.3 —— userdata (1)
- 快速掌握Lua 5.3 —— 函数
- 快速掌握Lua 5.3 —— Coroutines
- 快速掌握Lua 5.3 —— 数据结构
- 快速掌握Lua 5.3 —— 环境
- 快速掌握Lua 5.3 —— packages
- 快速掌握Lua 5.3 —— 资源管理
- 快速掌握Lua 5.3 —— "metatables" and "metamethods" (2)
- 快速掌握Lua 5.3 —— 字符串库 (2)
- 快速掌握Lua 5.3 —— I/O库 (2)
- 快速掌握Lua 5.3 —— 调试库 (2)
- lua——userdata使用
- 快速掌握Lua 5.3 —— 编写提供给Lua使用的C库函数的技巧 (2)
- 快速掌握Lua 5.3 —— 让我们开始吧
- 快速掌握Lua 5.3 —— 各种变量和值
- 快速掌握Lua 5.3 —— "Iterators"和"Generic for"
- 快速掌握Lua 5.3 —— 编译,运行以及错误
- 使ul的li元素居中对齐
- Android系统定制之bootanimation.zip的制作
- greenplum 日期及时间函数
- 键盘上,在Esc下面的按键,『~』
- ios 制作二维码 例子 QRcode
- 快速掌握Lua 5.3 —— userdata (2)
- Jetty的工作原理以及与Tomcat的比较
- Fragment中onOptionsItemSelected不响应
- Learning AngularJs
- scrapy捕获爬取失败的url
- iOS tableView卡顿的优化
- [C++Primer]序&前言
- C++基础实例-函数等(4)
- 北京大学生对基于物联网的一卡通系统试验研究