Lua
Lua扩展c程序
api
出入栈api
-
push 系列 (C -> Stack)
void lua_pushnil (lua_State * L); void lua_pushboolean (lua_State * L, int bool); void lua_pushnumber (lua_State * L, lua_Number n); // double void lua_pushinteger (lua_State * L, lua_Integer n); // integer void lua_pushlstring (lua_State * L, const char * s, size_t len); void lua_pushstring (lua_State * L, const char * s);
-
set 系列 (Stack -> Lua)
void lua_setglobal(lua_State * L, const char * name); void lua_settable(lua_State * L, int idx); void lua_setfield(lua_State * L, int idx, const char * k); void lua_seti(lua_State * L, int idx, lua_Integer n); void lua_rawset(lua_State * L, int idx); void lua_rawseti(lua_State * L, int idx, lua_Integer n); void lua_rawsetp(lua_State * L, int idx, const void * p); int lua_setmetatable(lua_State * L, int objindex); void lua_setuservalue(lua_State * L, int idx);
-
get 系列 (Lua -> Stack)
int lua_getglobal(lua_State *L, const char *name); int lua_gettable(lua_State *L, int idx); int lua_getfield(lua_State *L, int idx, const char *k); int lua_geti(lua_State *L, int idx, lua_Integer n); int lua_rawget(lua_State *L, int idx); int lua_rawgeti(lua_State *L, int idx, lua_Integer n); int lua_rawgetp(lua_State *L, int idx, const void *p); void lua_createtable(lua_State *L, int narr, int nrec); void* lua_newuserdata(lua_State *L, size_t sz); int lua_getmetatable(lua_State *L, int objindex); int lua_getuservalue(lua_State *L, int idx);
获取栈元素
-
_is 和 _to 系列,不会出栈。
int lua_isnumber(lua_State *L, int idx); int lua_isstring(lua_State *L, int idx); int lua_iscfunction(lua_State *L, int idx); int lua_isinteger(lua_State *L, int idx); int lua_isuserdata(lua_State *L, int idx); int lua_type(lua_State *L, int idx); const char* lua_typename(lua_State *L, int tp); lua_Number lua_tonumberx(lua_State *L, int idx, int *isnum); lua_Integer lua_tointegerx(lua_State *L, int idx, int *isnum); int lua_toboolean(lua_State *L, int idx); const char* lua_tolstring(lua_State *L, int idx, size_t *len); size_t lua_rawlen(lua_State *L, int idx); lua_CFunction lua_tocfunction(lua_State *L, int idx); void* lua_touserdata(lua_State *L, int idx); lua_State* lua_tothread(lua_State *L, int idx); const void* lua_topointer(lua_State *L, int idx);
-
check 系列
// 检查函数的第 arg 个参数是否是一个 数字,并返回这个数字 lua_Number luaL_checknumber(lua_State *L, int arg); // 检查函数的第 arg 个参数是否是一个 字符串并返回这个字符串 const char *luaL_checkstring (lua_State *L, int arg);
栈管理api
-
常用宏函数
// 弹出栈顶 n 个元素 #define lua_pop(L,n) lua_settop(L, -(n) - 1) // 移除栈中索引"index"处的元素, 该元素之上的所有元素下移 #define lua_remove(L,idx) (lua_rotate(L, (idx), -1), lua_pop(L, 1)) // 将栈顶元素移动到索引"index"处, 索引"index"(含)之上的所有元素上 上移 #define lua_insert(L,idx) lua_rotate(L, (idx), 1)
-
为发防止进栈溢出, 有如下函数可用
int lua_checkstack (lua_State *L, int sz); void luaL_checkstack (lua_State *L, int sz, const char *msg);
-
基本函数
// 返回栈顶元素的索引。因为栈中元素的索引是从 1 开始编号的, 所以函数的返回值相当于栈中元素的个数。返回值为 0 表示栈为空。 int lua_gettop(lua_State *L); //设置栈顶为索引"index"指向处。如果"index"比"lua_gettop()"的值大, 那么多出的新元素将被赋值为"nil"。lua_settop(L, 0); 清空栈。 void lua_settop(lua_State *L, int index); // 将索引"index"处元素, 压到栈顶。(把栈上给定索引处的元素作一个副本压栈) void lua_pushvalue (lua_State *L, int index); // 将栈顶元素拷贝到索引"index"处。(栈顶出栈,覆盖了索引"index"处的元素) void lua_replace(lua_State *L, int index); // 把从 从 idx 开始到栈顶的元素 轮转 n 个位置。 void lua_rotate (lua_State *L, int index, int n);
数据类型宏
-
Lua基本数据类型
#define LUA_TBOOLEAN 1 #define LUA_TLIGHTUSERDATA 2 #define LUA_TNUMBER 3 #define LUA_TSTRING 4 #define LUA_TTABLE 5 #define LUA_TFUNCTION 6 #define LUA_TUSERDATA 7 #define LUA_TTHREAD 8
测试
extern "C"{
#include <lua.h>
#include <lualib.h>
#include <lauxlib.h>
}
void stackDump(lua_State *L) {
int count = 0;
printf("begin dump lua stack %d\n", count);
int top = lua_gettop(L);
for (int i=1; i <= top; ++i) {
int t = lua_type(L, i);
switch (t)
{
case LUA_TSTRING:
printf("'%s'\n", lua_tostring(L, i));
break;
case LUA_TBOOLEAN:
printf(lua_toboolean(L, i) ? "true\n" : "false\n");
break;
case LUA_TNUMBER:
printf("%g\n", lua_tonumber(L, i));
break;
default:
printf("%s\n", lua_typename(L, t));
break;
}
}
}
int main(int argc, char **argv) {
printf("%s\n",argv[0]);
lua_State *L = luaL_newstate();
luaL_openlibs(L);
stackDump(L);
lua_pushinteger(L, 1);
lua_pushinteger(L, 2);
lua_pushinteger(L, 3);
lua_pushinteger(L, 4);
stackDump(L);
int n = lua_gettop(L);
printf("stack size = %d\n", n);
//lua_settop(L, 2);
//stackDump(L);
// lua_pop(L, 1);
//lua_pushvalue(L, 2);
lua_replace(L, 1);
stackDump(L);
// lua_rotate(L, 1, -1);
lua_insert(L, -2);
stackDump(L);
luaL_dofile(L, "test.lua");
lua_close(L);
return 0;
}
/* output
./build/main
begin dump lua stack 0
begin dump lua stack 0
1
2
3
4
stack size = 4
begin dump lua stack 0
4
2
3
begin dump lua stack 0
4
3
2
test lua...
*/
Lua扩展C
访问Lua全局变量
int lua_getglobal (lua_State *L, const char *name);
// 将 lua 全局作用域中变量名为 name 的成员压入虚拟栈中
测试:
test.lua
price = 9999
name = "kirito"
c
extern "C"{
#include <lua.h>
#include <lualib.h>
#include <lauxlib.h>
}
void stackDump(lua_State *L) {
int count = 0;
printf("begin dump lua stack %d\n", count);
int top = lua_gettop(L);
for (int i=1; i <= top; ++i) {
int t = lua_type(L, i);
switch (t)
{
case LUA_TSTRING:
printf("'%s'\n", lua_tostring(L, i));
break;
case LUA_TBOOLEAN:
printf(lua_toboolean(L, i) ? "true\n" : "false\n");
break;
case LUA_TNUMBER:
printf("%g\n", lua_tonumber(L, i));
break;
default:
printf("%s\n", lua_typename(L, t));
break;
}
}
}
int main(int argc, char **argv) {
lua_State *L = luaL_newstate();
luaL_openlibs(L);
int ret = luaL_dofile(L, "test2.lua");
printf("ret = %d\n", ret);
lua_getglobal(L, "price");
int price = lua_tointeger(L, -1);
printf("price = %d\n", price);
lua_getglobal(L, "name");
const char *name = lua_tostring(L, -1);
printf("name = %s\n", name);
stackDump(L);
lua_pop(L, 2);
stackDump(L);
lua_close(L);
return 0;
}
/*
ret = 0
price = 9999
name = kirito
begin dump lua stack 0
9999
'kirito'
begin dump lua stack 0
*/
访问Lua全局表字段
void lua_gettable (lua_State *L, int index);
// 把 t[k] 值压入堆栈,这里的 t 是指有效索引 index 指向的值,而 k 则是栈顶放的值。
// 这个函数会弹出堆栈上的 key,把结果放在栈上原来 key 的相同位置。
int lua_getfield (lua_State *L, int index, const char *k);
// lua_getfield(stack, -1, "loaded");
// 等 价 于 lua_pushstring(L, "loaded"), lua_gettable(L, -2);
测试:
test.lua
mytab = {price = 9999, name = "kirito"}
c
extern "C"{
#include <lua.h>
#include <lualib.h>
#include <lauxlib.h>
}
void stackDump(lua_State *L) {
int count = 0;
printf("begin dump lua stack %d\n", count);
int top = lua_gettop(L);
for (int i=1; i <= top; ++i) {
int t = lua_type(L, i);
switch (t)
{
case LUA_TSTRING:
printf("'%s'\n", lua_tostring(L, i));
break;
case LUA_TBOOLEAN:
printf(lua_toboolean(L, i) ? "true\n" : "false\n");
break;
case LUA_TNUMBER:
printf("%g\n", lua_tonumber(L, i));
break;
default:
printf("%s\n", lua_typename(L, t));
break;
}
}
}
int main(int argc, char **argv) {
lua_State *L = luaL_newstate();
luaL_openlibs(L);
int ret = luaL_dofile(L, "test3.lua");
printf("ret = %d\n", ret);
lua_getglobal(L, "mytab");
// lua_pushstring(L, "price"); //-1 -2
// lua_gettable(L, , -2);
lua_getfield(L, -1, "price");
int price = lua_tonumber(L, -1); //将 k=price 替换成了 v = 9999
printf("price = %d\n", price);
stackDump(L);
lua_settop(L, 1);
lua_getfield(L, -1, "name");
const char *name = lua_tostring(L, -1);
printf("name = %s\n", name);
stackDump(L);
lua_pop(L, 2);
stackDump(L);
lua_close(L);
return 0;
}
/*
ret = 0
price = 9999
begin dump lua stack 0
table
9999
name = kirito
begin dump lua stack 0
table
'kirito'
begin dump lua stack 0
*/
访问Lua全局函数
int luaL_dofile (lua_State *L, const char *filename);
// 加载并运行文件 是个宏定义
// luaL_loadfile(L, filename) || lua_pcall(L, 0, LUA_MULTRET,0)
int luaL_loadfile (lua_State *L, const char *filename);
// 调用 load 函数,加载文件并编译文件为 lua 的 chunk,然后将其推到栈顶。
int lua_load(lua_State *L,
lua_Reader reader,
void *data,
const char *chunkname,
const char *mode);
// 加载一段 Lua 代码块,但不运行它。 如果没有错误, lua_load 把一个编译好的代码
// 块作为一个 Lua 函数压到栈顶。 否则,压入错误消息。
int lua_pcall (lua_State *L, int nargs, int nresults, int msgh);
// 安全模式下的,lua_call。通常,最后一个参数填零
// if msgh == 0 then the error object returned on the stack is exactly the original error object
void lua_call (lua_State *L, int nargs, int nresults);
// 要想调用一个 lua 函数,流程如下,
// 第一,函数必须被压栈
// 第二,依次序压入参数,调用 lua_call,nargs 是入栈参数的个数。
// 第三,函数调用后,函数及其参数要出栈,
// 第四,返回值入栈,入栈顺序,先入栈者底,后入栈者顶,nresults 填入返回值的个数。
测试:
test.lua
function myfunc( name, a, b)
return "my name is "..name , a+b
end
c
extern "C"{
#include <lua.h>
#include <lualib.h>
#include <lauxlib.h>
}
void stackDump(lua_State *L) {
int count = 0;
printf("begin dump lua stack %d\n", count);
int top = lua_gettop(L);
for (int i=1; i <= top; ++i) {
int t = lua_type(L, i);
switch (t)
{
case LUA_TSTRING:
printf("'%s'\n", lua_tostring(L, i));
break;
case LUA_TBOOLEAN:
printf(lua_toboolean(L, i) ? "true\n" : "false\n");
break;
case LUA_TNUMBER:
printf("%g\n", lua_tonumber(L, i));
break;
default:
printf("%s\n", lua_typename(L, t));
break;
}
}
}
int main(int argc, char **argv) {
lua_State *L = luaL_newstate();
luaL_openlibs(L);
int ret = luaL_dofile(L, "test4.lua");
printf("ret = %d\n", ret);
lua_getglobal(L, "myfunc");
lua_pushstring(L, "kirito");
lua_pushinteger(L, 1);
lua_pushnumber(L, 3.14);
stackDump(L);
lua_pcall(L, 3, 2, 0);
const char * name = lua_tostring(L, -2);
double a = lua_tonumber(L, -1);
stackDump(L);
printf("return %s, %lf\n", name, a);
lua_close(L);
return 0;
}
/*
ret = 0
begin dump lua stack 0
function
'kirito'
1
3.14
begin dump lua stack 0
'my name is kirito'
4.14
return my name is kirito, 4.140000
*/
C扩展Lua
Lua可以调用C的函数,必须先注册注册函数,即以一种恰当的方式为Lua提供C函数的地址。
Lua调用C函数时,也使用了一个与C调用Lua函数时相同类型的栈,C函数从栈中获取参数,并将结果压入栈。注意此处栈不是一个全局的栈,每个函数都用私有局部栈,Lua调用C时,第一个参数总是位于局部栈索引1的位置,栈底
无论何时 Lua 调用 C, 被调用的函数都得到一个 新的栈,这个栈于 独立于 C 函数本身
的栈,也独立于之前的 Lua 栈。它里面包含了 Lua 传递给 C 函数的所有参数,而 C 函
数则把要返回的结果放入这个栈以返回给调用者。
Lua访问C入栈的值
api
void lua_setglobal (lua_State *L, const char *name);
// 将虚拟栈中,将栈顶元素弹出,作为全局 lua 变量 name 的值。
void lua_newtable (lua_State *L);
// 产生一个空表, 并推入栈
void lua_settable (lua_State *L, int index);
// 作一个等价于 t[k] = v 的操作,这里 t 是一个给定有效索引 index 处的值,v 指栈顶的值,而 k 是栈顶之下的那个值。
// 把栈顶作为 value,栈顶的下一个作为 key 设置到 index 指向的 table,最后把这两个全部弹出栈,这时候 settable 完成。
// lua_pushstring(L, "name");
// lua_pushstring(L, "123");
// lua_settable(L, -3);
void lua_setfield (lua_State *L, int index, const char *k);
// 等价于 t[k] = v,t 是栈上索引为 index 的表,v 是栈顶的值。函数结束,栈顶值v 会被弹出。
// lua_pushstring(L, "name");
// lua_pushstring(L, "123");
// lua_settable(L, -3);
// 等价于
// lua_pushstring(L,"123"); //此两句,可顶上三句
// lua_setfield(L, -2, "name");
测试:
test.lua
print("in lua ...")
print(name)
print(price)
print(t.name)
print(t.price)
c
extern "C"{
#include <lua.h>
#include <lualib.h>
#include <lauxlib.h>
}
void stackDump(lua_State *L) {
int count = 0;
printf("begin dump lua stack %d\n", count);
int top = lua_gettop(L);
for (int i=1; i <= top; ++i) {
int t = lua_type(L, i);
switch (t)
{
case LUA_TSTRING:
printf("'%s'\n", lua_tostring(L, i));
break;
case LUA_TBOOLEAN:
printf(lua_toboolean(L, i) ? "true\n" : "false\n");
break;
case LUA_TNUMBER:
printf("%g\n", lua_tonumber(L, i));
break;
default:
printf("%s\n", lua_typename(L, t));
break;
}
}
}
int main(int argc, char **argv) {
lua_State *L = luaL_newstate();
luaL_openlibs(L);
int price = 9999;
const char *name = "kirito";
lua_pushnumber(L, price);
lua_setglobal(L, "price");
stackDump(L);
lua_pushstring(L, name);
lua_setglobal(L, "name");
stackDump(L);
lua_newtable(L);
lua_pushstring(L, "price");
lua_pushinteger(L, 100);
lua_settable(L, -3);
lua_pushstring(L,"kirito"); //此两句,可顶上三句
lua_setfield(L, -2, "name");
lua_setglobal(L, "t");
stackDump(L);
int ret = luaL_dofile(L, "test5.lua");
printf("ret = %d\n", ret);
lua_close(L);
return 0;
}
/*
begin dump lua stack 0
begin dump lua stack 0
begin dump lua stack 0
in lua ...
kirito
9999.0
kirito
100
ret = 0
*/
Lua调用C函数
api
typedef int (*lua_CFunction) (lua_State *L);
void lua_pushcfunction (lua_State *L, n lua_CFunction f);
// 将函数压入栈,该函数接受一个 C 类型的函数指针,并将其以 lua function 形式入栈。
// 在 lua 中调用该函数即会发生 c 函数的调用。
int foo(lua_State *L)
{
int n = lua_gettop(L); // 栈顶idx,就是参数个数
int sum = 0;
for (int i=1; i<=n; ++i) {
if (!lua_isnumber(L,i)) {
lua_pushliteral(L, "incorrect argument");
lua_error(L); // 返回
}
sum += lua_tonumber(L,i);
}
lua_pushnumber(L, sum/n);
lua_pushnumber(L, sum);
return 2; // 返回值个数
}
void lua_register (lua_State *L, const char *name, lua_CFunction f);
// 其本质等同于先 pushcfunction,然后再 setglobal。
测试:
test.lua
a, b = foo(1,2,3,4);
print(a)
print(b)
c
extern "C"{
#include <lua.h>
#include <lualib.h>
#include <lauxlib.h>
}
void stackDump(lua_State *L) {
int count = 0;
printf("begin dump lua stack %d\n", count);
int top = lua_gettop(L);
for (int i=1; i <= top; ++i) {
int t = lua_type(L, i);
switch (t)
{
case LUA_TSTRING:
printf("'%s'\n", lua_tostring(L, i));
break;
case LUA_TBOOLEAN:
printf(lua_toboolean(L, i) ? "true\n" : "false\n");
break;
case LUA_TNUMBER:
printf("%g\n", lua_tonumber(L, i));
break;
default:
printf("%s\n", lua_typename(L, t));
break;
}
}
}
int func_return_table(lua_State *L)
{
lua_newtable(L); //创建一个表格, 放在栈顶
lua_pushstring(L, "key"); //压入 key
lua_pushnumber(L, 66); //压入 value
lua_settable(L, -3); //弹出 key, value, 并设置到 table 里面去
lua_pushstring(L,"foo");
lua_pushcfunction(L,foo);
lua_settable(L, -3); //
return 1;
}
int foo(lua_State *L)
{
int n = lua_gettop(L); // 栈顶idx,就是参数个数
int sum = 0;
for (int i=1; i<=n; ++i) {
if (!lua_isnumber(L,i)) {
lua_pushliteral(L, "incorrect argument");
lua_error(L);
}
sum += lua_tonumber(L,i);
}
lua_pushnumber(L, sum/n);
lua_pushnumber(L, sum);
return 2; // 返回值个数
}
int main(int argc, char **argv) {
lua_State *L = luaL_newstate();
luaL_openlibs(L);
lua_register(L, "foo", foo);
int ret = luaL_dofile(L, "test6.lua");
printf("ret = %d\n", ret);
lua_close(L);
return 0;
}
/*
2.0
10.0
ret = 0
*/
c函数批量注册
api
typedef struct luaL_Reg
{
const char *name;
lua_CFunction func;
} luaL_Reg;
// 用于存放,函数指针和注册的函数名。常用于生成数组,数组的最后一个元素,一定是以{NULL,NULL}结尾
// 等价于 luaL_newlibtable(L,l),luaL_setfuncs(L,l,0)
void luaL_newlib (lua_State *L, const luaL_Reg l[]);
// luaL_newlib 也是一个宏函数,简化了创建表和循环注册函数
void luaL_newlibtable (lua_State *L, const luaL_Reg l[]);
// 创建一张新的表,并预分配足够保存下数组 l 内容的空间(但不填充)
void luaL_setfuncs (lua_State *L, const luaL_Reg *l, int nup);
// 设置数组 l 中所有函数的到栈顶的表中 第三个参数通常为 0
void luaL_requiref (lua_State *L,
const char *modname,
lua_CFunction openf,
int glb);
// 如果 modname 不在 package.loaded 中,则调用 openf 函数以 modname 为参数,使其为 package.loaded[modname]。其行为类似于 require,如果 glb 为 true,则存储模块到全局的 modname。
测试:
test.lua
print(my.add(1,2))
print(my.foo(1,2))
c
extern "C"{
#include <lua.h>
#include <lualib.h>
#include <lauxlib.h>
}
void stackDump(lua_State *L) {
int count = 0;
printf("begin dump lua stack %d\n", count);
int top = lua_gettop(L);
for (int i=1; i <= top; ++i) {
int t = lua_type(L, i);
switch (t)
{
case LUA_TSTRING:
printf("'%s'\n", lua_tostring(L, i));
break;
case LUA_TBOOLEAN:
printf(lua_toboolean(L, i) ? "true\n" : "false\n");
break;
case LUA_TNUMBER:
printf("%g\n", lua_tonumber(L, i));
break;
default:
printf("%s\n", lua_typename(L, t));
break;
}
}
}
int foo(lua_State *L)
{
int n = lua_gettop(L); // 栈顶idx,就是参数个数
int sum = 0;
for (int i=1; i<=n; ++i) {
if (!lua_isnumber(L,i)) {
lua_pushliteral(L, "incorrect argument");
lua_error(L);
}
sum += lua_tonumber(L,i);
}
lua_pushnumber(L, sum/n);
lua_pushnumber(L, sum);
return 2; // 返回值个数
}
int add(lua_State *L)
{
int n = lua_gettop(L);
int sum = 0;
for (int i=0; i<n; ++i) {
sum+=lua_tonumber(L, i+1);
}
if (n!=0) {
lua_pushnumber(L, sum);
return 1;
}
return 0;
}
const luaL_Reg lib[] =
{
{"foo", foo},
{"add", add},
{NULL,NULL}
};
int luaopen_my(lua_State *L) {
luaL_newlib(L, lib);
return 1;
}
int main(int argc, char **argv) {
lua_State *L = luaL_newstate();
luaL_openlibs(L);
// 统一注册lua中调用的函数
luaL_requiref(L, "my", luaopen_my, 1);
stackDump(L);
int ret = luaL_dofile(L, "test7.lua");
printf("ret = %d\n", ret);
lua_close(L);
return 0;
}
/*
begin dump lua stack 0
table
3.0
1.0 3.0
ret = 0
*/
c++生成dll/so
c
extern "C"{
#include <lua.h>
#include <lualib.h>
#include <lauxlib.h>
}
int foo(lua_State *L)
{
int n = lua_gettop(L); // 栈顶idx,就是参数个数
int sum = 0;
for (int i=1; i<=n; ++i) {
if (!lua_isnumber(L,i)) {
lua_pushliteral(L, "incorrect argument");
lua_error(L);
}
sum += lua_tonumber(L,i);
}
lua_pushnumber(L, sum/n);
lua_pushnumber(L, sum);
return 2; // 返回值个数
}
int add(lua_State *L)
{
int n = lua_gettop(L);
int sum = 0;
for (int i=0; i<n; ++i) {
sum+=lua_tonumber(L, i+1);
}
if (n!=0) {
lua_pushnumber(L, sum);
return 1;
}
return 0;
}
const luaL_Reg lib[] =
{
{"foo", foo},
{"add", add},
{NULL,NULL}
};
extern "C"{
// luaopen_xx xx必须和最后生成库的名字一致 比如 my.so luaopen_my
int luaopen_my(lua_State *L) {
luaL_newlib(L, lib);
return 1;
}
}
lua
-- 动态库名字改成my.so
my=require("my")
print(my.add(1,2))
print(my.foo(1,2))
Lua
环境安装
- 官网 www.lua.org
$ curl -LO http://www.lua.org/ftp/lua-5.3.5.tar.gz
$ tar -xzf lua-5.3.5.tar.gz
$ cd lua-5.3.5/
# 依赖 libreadline-dev
$ make linux test
$ sudo make install
$ lua -v # 检查
简介
数据类型
类型 | 描述 |
---|---|
nil | 无效值 |
boolean | false与true |
number | 相当于double |
string | 'str' 或者"str" |
function | C或Lua函数 |
userdata | 存储在变量中的C数据结构 |
thread | 协程 |
table | 关联数组 |
语法
-- 注释
--[[
多行注释
]]
print("Hello World")
--[[关键词
and break do else
elseif end false for
function if in local
nil not or repeat return
then true until while goto
一般约定,以下划线开头连接一串大写字母的名字(比如 _VERSION)被保留用于 Lua 内部全局变量。
]]
print(type("Hello world")) --> string
print(type(10.4*3)) --> number
print(type(print)) --> function
print(type(type)) --> function
print(type(true)) --> boolean
print(type(nil)) --> nil
print(type(type(X))) --> string
-- 给全局变量或者 table 表里的变量赋一个 nil 值,等同于把它们删掉
tab1 = { key1 = "val1", key2 = "val2", "val3" }
for k, v in pairs(tab1) do
print(k .. " - " .. v)
end
type(X)=="nil" -- 作比较应该加双引号
-- false 和 nil 看作是 false,其他的都为 true,数字 0 也是 true
if false or nil then
print("至少有一个是 true")
else
print("false 和 nil 都为 false")
end
-- 可以用方括号表示一块字符串
str = [[
123
124
]]
-- 在对一个数字字符串上进行算术操作时,Lua 会尝试将这个数字字符串转成一个数字
-- 字符串连接使用的是 ..
print("str" .. 1) -- str1
print(123 .. 123) -- 123123 数值连接
-- 使用 # 来计算字符串的长度
str = "123"
print(#str)
print(#"123")
-- local 局部变量 省略为全局变量
local tab = {}
local tbl2 = {"apple", "pear", "orange", "grape"} -- 默认初始索引一般以1开始
function factorial1(n)
if n == 0 then
return 1
else
return n * factorial1(n - 1)
end
end
factorial2 = factorial1
-- 赋值
x = 1
x, y = y, x
a, b = f() -- f可以多参返回,返回少了就是nil
-- 对于table
t[i]
t.i -- 当索引为字符串类型时的一种简化写法
gettable_event(t,i) -- 采用索引访问本质上是一个类似这样的函数调用
循环
while( a < 20 )
do
print("a 的值为:", a)
a = a+1
end
-- var 从 exp1 变化到 exp2,每次变化以 exp3 为步长递增 var,并执行一次 "执行体"。exp3 是可选的,如果不指定,默认为1。
for var=exp1,exp2,exp3 do
<执行体>
end
for i=1,f(x) do
print(i)
end
for i=10,1,-1 do
print(i)
end
a = {"one", "two", "three"}
for i, v in ipairs(a) do
print(i, v)
end
repeat
print("a的值为:", a)
a = a + 1
until( a > 15 )
流程控制
--[ 0 为 true ]
if(0)
then
print("0 为 true")
end
if( a == 10 )
then
print("a 的值为 10" )
elseif( a == 20 )
then
print("a 的值为 20" )
elseif( a == 30 )
then
print("a 的值为 30" )
else
print("没有匹配 a 的值" )
end
print("a 的真实值为: ", a )
函数
local function max(num1, num2)
if (num1 > num2) then
result = num1;
else
result = num2;
end
return result;
end
function maximum (a)
local mi = 1 -- 最大值索引
local m = a[mi] -- 最大值
for i,val in ipairs(a) do
if val > m then
mi = i
m = val
end
end
return m, mi
end
print(maximum({8,10,23,12,5}))
-- 可变参
function add(...)
-- select("#",...) 来获取可变参数的数量
print("总共传入 " .. select("#",...) .. " 个数")
local s = 0
for i, v in ipairs{...} do --> {...} 表示一个由所有变长参数构成的数组
s = s + v
end
return s
end
print(add(3,4,5,6,7)) --->25
function fwrite(fmt, ...) ---> 固定的参数fmt
return io.write(string.format(fmt, ...))
end
function foo(...)
for i = 1, select('#', ...) do -->获取参数总数
local arg = select(i, ...); -->读取参数
print("arg", arg);
end
end
foo(1, 2, 3, 4);
运算符
+ - * / % ^(乘幂)
== ~= > < >= <=
and or not
..(连接符 两个点!)
#(一元运算符,返回字符串或表的长度)
数组
-- 初始化多维数组
array = {}
for i=1,3 do
array[i] = {}
for j=1,3 do
array[i][j] = i*j
end
end
-- 访问数组
for i=1,3 do
for j=1,3 do
print(array[i][j])
end
end
迭代器
-- 泛型 for 迭代器
-- 泛型 for 在自己内部保存迭代函数,实际上它保存三个值:迭代函数、状态常量、控制变量。
for k, v in pairs(t) do
print(k, v)
end
-- 使用了 Lua 默认提供的迭代函数 ipairs
array = {"Google", "Runoob"}
for key,value in ipairs(array)
do
print(key, value)
end
-- 无状态的迭代器
function square(iteratorMaxCount,currentNumber)
if currentNumber<iteratorMaxCount
then
currentNumber = currentNumber+1
return currentNumber, currentNumber*currentNumber
end
end
-- 泛型 for 需要三个值:迭代函数、状态常量、控制变量
-- 对于 for 结构来说,状态常量没有用处,仅初始化用
for i,n in square,3,0
do
print(i,n)
end
function iter (a, i)
i = i + 1
local v = a[i]
if v then
return i, v
end
end
function ipairs (a)
return iter, a, 0
end
-- 多状态的迭代器
array = {"Google", "Runoob"}
function elementIterator (collection)
local index = 0
local count = #collection
-- 闭包函数
return function ()
index = index + 1
if index <= count
then
-- 返回迭代器的当前元素
return collection[index]
end
end
end
for element in elementIterator(array)
do
print(element)
end
模块与包
-- 文件名为 module.lua
-- 定义一个名为 module 的模块
module = {}
-- 定义一个常量
module.constant = "这是一个常量"
-- 定义一个函数
function module.func1()
io.write("这是一个公有函数!\n")
end
local function func2()
print("这是一个私有函数!")
end
function module.func3()
func2()
end
return module
--------------------------------------使用包
-- test_module.lua 文件
-- module 模块为上文提到到 module.lua
module = require("module")
print(module.constant)
module.func3()
--[[
对于自定义的模块,模块文件不是放在哪个文件目录都行,函数 require 有它自己的文件路径加载策略,它会尝试从 Lua 文件或 C 程序库中加载模块。
require 用于搜索 Lua 文件的路径是存放在全局变量 package.path 中,当 Lua 启动后,会以环境变量 LUA_PATH 的值来初始这个环境变量。如果没有找到该环境变量,则使用一个编译时定义的默认路径来初始化。
#LUA_PATH
export LUA_PATH="~/lua/?.lua;;"
文件路径以 ";" 号分隔,最后的 2 个 ";;" 表示新加的路径后面加上原来的默认路径。
]]
-----c 包
local path = "/usr/local/lua/lib/libluasocket.so"
local f = loadlib(path, "luaopen_socket")
local path = "/usr/local/lua/lib/libluasocket.so"
-- 或者 path = "C:\\windows\\luasocket.dll",这是 Window 平台下
local f = assert(loadlib(path, "luaopen_socket"))
f() -- 真正打开库
协程
方法 | 描述 |
---|---|
coroutine.create() | 创建 coroutine,返回 coroutine, 参数是一个函数,当和 resume 配合使用的时候就唤醒函数调用 |
coroutine.resume() | 重启 coroutine,和 create 配合使用 |
coroutine.yield() | 挂起 coroutine,将 coroutine 设置为挂起状态,这个和 resume 配合使用能有很多有用的效果 |
coroutine.status() | 查看 coroutine 的状态 注:coroutine 的状态有三种:dead,suspended,running,具体什么时候有这样的状态请参考下面的程序 |
coroutine.wrap() | 创建 coroutine,返回一个函数,一旦你调用这个函数,就进入 coroutine,和 create 功能重复 |
coroutine.running() | 返回正在跑的 coroutine,一个 coroutine 就是一个线程,当使用running的时候,就是返回一个 corouting 的线程号 |