LUA相关
lua和c++互相调用
要包含lua相关的文件,然后#include "lua\lua.hpp"
在c++中建立一个状态lua_State,以后所有的调用lua相关的代码都要带这个参数
lua_State * L = luaL_newstate();
加载所有的库
luaL_openlibs(L);
最后关闭状态通过
lua_close(L);
一个C函数被LUA调用的时候,参数通过lua_State获取,lua_State代表一个独立的线程,里面虚拟了一个栈,跟函数自己的栈没有关系,通过这个虚拟栈,可以通过lua_gettop(L)获取Lua传给C的参数个数,通过 lua_tonumber(L, i) 等获取第i个参数,参数的索引是几就是代表Lua传入的第几个参数,通过 lua_pushnumber(L, ret) 等返回值,可以返回多个值,最后通过函数的返回值(return num;)告诉Lua它返回了多少个返回值。
int lua_checkstack (lua_State *L, int n);可以检查是否有n个堆栈位置
如果索引值是负数,有n个参数,那-1代表栈顶,-n代表栈底
openresty加载的lua文件和so文件的路径分别是
;/usr/local/openresty/lualib/?.lua;/usr/local/openresty/lualib/?/?.lua;/usr/local/openresty/nginx/app/?.lua;/usr/local/openresty/nginx/app/?/?.lua;/usr/local/openresty/luajit/share/luajit-2.1.0-beta3/jit/?.lua;
/usr/local/openresty/site/lualib/?.so;/usr/local/openresty/lualib/?.so;./?.so;/usr/local/lib/lua/5.1/?.so;/usr/local/openresty/luajit/lib/lua/5.1/?.so;/usr/local/lib/lua/5.1/loadall.so
在openresty中编译so库,依赖的lua的库在/usr/local/openresty/luajit/lib和.,对应的库是libluajit-5.1.so和libdl.so,libluajit-5.1.so是个符号连接,连接到真正的库是同文件夹下的libluajit-5.1.so.2.1.0,头文件在/usr/local/openresty/luajit/include/luajit-2.1中,而生成的库需要放到/usr/local/openresty/lualib中,就能直接调用,使用require("库的全名去掉.so"),不需要ffi这种调用so库的机制
openresty的lua解析器是/usr/local/openresty/luajit/bin/luajit,这也是一个符号连接,连接到同目录下的一个可执行文件
这套语法有点繁琐,可以选用ffi的方式,直接调用C函数库
local ffi = require("ffi") -- 加载ffi库 --将libtest.so加入到so库的加载路径里 --ffi.load("test",ture) --ffi.C.show(str) 调用函数 local myffi = ffi.load("test") -- 加载动态库 --[[ #include <stdio.h> int show(char *str) { int ret = 0; if(str == NULL){ ret = -1; } else{ printf("输入:%s\n",str); } return ret; } ]] -- 所有使用的库函数都要对其进行声明,类似C语言引入.h头文件 ffi.cdef [[ int show(char* str); ]] local lua_str = "Hello World" local cstr_t = ffi.typeof("char*") --[[ 语法: cdata = ffi.cast(ct, init) 功能: 创建一个 scalar cdata 对象。 ]] local cstr = ffi.cast(cstr_t, lua_str) print(myffi.show(cstr))
返回
输入:Hello World
0
成员方法的定义:
function obj:method(a1, a2, ...)
...
end
等价于
function obj.method(self, a1, a2, ...)
...
end
等价于
obj.method = function (self, a1, a2, ...)
...
end
成员方法的调用:
obj:method(a1, a2, ...)
等价于
obj.method(obj, a1, a2, ...)
函数闭包:
函数和函数引用的在函数之外的局部变量构成一个闭包,这个函数之外的局部变量跟函数的生存期绑在一起,不会失效。
function createCountdownTimer(second) local ms = second * 1000 --ms为countDown的Upvalue local function countDown() ms = ms -1 return ms end return countDown end local timer1 = createCountdownTimer(1) for i = 1, 3 do print(timer1()) end
元表
通过这个方法设置一个table对象的元表(metatable)
setmetatable(table,metatable)
如果元表(metatable)中存在__metatable键值,setmetatable会失败
如果有返回值,返回值就是table参数对应的对象
通过 getmetatable(table) 返回对象的元表(metatable)
__index
如果一个table对象的键找不到,就去这个对象的元表对象里找键 __index 对应的键值,这个键值如果是一个table对象,就去这个table对象里找,找不到就真找不到了;如果这个键值是一个函数,就调用这个函数,传入这个table对象和键,返回键值
__newindex
如果要给一个没有的键值赋值,就先去找键__newindex对应的table或函数,如果有这个键值,就调用这个键值的table或函数赋值,没有才在这个table赋值
__call
如果调用函数func(args)时,函数名func对应的类型不是function,就在func的metatable里找__call来调用,传入参数args,返回值可以有多个。
还有很多元表方法,可以方便操作table,先不写了
原型和派生:
一个对象既是一个普通的对象,同时也可以作为创建其他对象的原型的对象(即类对象,class object)
动态的改变原型对象的属性就可以动态的影响所有基于此原型的对象
基于一个原型被创建出来的对象可以重载任何属于这个原型对象的方法、属性而不影响原型对象
基于原型被创建出来的对象还可以作为原型来创建其他对象。
local Robot = { name = "Sam", id = 001 } function Robot:New(extension) local t = setmetatable(extension or { }, self) self.__index = self return t end function Robot:SetName(name) self.name = name end function Robot:GetName() return self.name end function Robot:SetId(id) self.id = id end function Robot:GetId() return self.id end robot = Robot:New() print("robot's name:", robot:GetName()) print("robot's id:", robot:GetId()) print("-----------------") local FootballRobot = Robot:New({position = "right back"}) function FootballRobot:SetPosition(p) self.position = p end function FootballRobot:GetPosition() return self.position end fr = FootballRobot:New() print("fr's position:", fr:GetPosition()) print("fr's name:", fr:GetName()) print("fr's id:", fr:GetId()) print("-----------------") --改原型 Robot:SetName("Bob") print("fr's name:", fr:GetName()) print("robot's name:", robot:GetName()) print("-----------------") --改派生对象 fr:SetName("Tom") print("fr's name:", fr:GetName()) print("robot's name:", robot:GetName())
包:
包文件一般在当前脚本文件的当前文件夹下,如果找不到,就到lualib文件夹下找,如果包含的文件有文件夹,就用.分割,最后的扩展名.lua不写
hello.lua
local pack = require "mypack" --导入包[注:包的名字与定义包的文件的名字相同(除去文件名后缀,在前面的代码中,就是“mypack”)] print(ver or "No ver defined!") print(pack.ver) pack.aFunInMyPack() print(aFunInMyPack or "No aFunInMyPack defined!") aFuncFromMyPack()
mypack.lua
module(..., package.seeall) --定义包 ver = "0.1 alpha" function aFunInMyPack() print("Hello!") end _G.aFuncFromMyPack = aFunInMyPack
输出结果:
No ver defined!
0.1 alpha
Hello!
No aFunInMyPack defined!
Hello!