Lua_Notes
lua脚本语言学习记录
Vim下Lua的补全(只能实现到支持Lua标准库)
使用Vundle + vim-lua-ftplugin + vim-misc
1、安装Vundle
2、在命令行输入vim ~/.vimrc对.vimrc文件进行修改
3、在My Bundles here:下加入,并保存退出:
Bundle ‘xolox/vim-lua-ftplugin’
Bundle ‘xolox/vim-misc’
4、开启vim,输入:BundleInstall,安装vim-lua-ftplugin和vim-misc插件,重启vim即可使用补全
C/C++中嵌入Lua脚本
Lua文件:
function test_print()
print("test!")
end
CPP文件:
#include<iostream>
extern "C"{
#include<lua.h>
#include<lualib.h>
#include<lauxlib.h>
}
using namespace std;
int main()
{
lua_State *L = luaL_newstate();
luaL_openlibs(L);//加载lua通用扩展库
if(L == NULL)
cout << "Lua Error" << endl;
if(luaL_loadfile(L, "test.lua") != LUA_OK)//载入lua脚本
cout << "Load File Error!" << endl;
if(lua_pcall(L, 0, 0, 0))//加载完lua文件后需要先运行一遍文件,此后才可以对文件内容操作
cout << "Load lua field error!" << endl;
lua_getglobal(L, "test_print");//将函数压入栈中
if(lua_pcall(L, 0, 0, 0))//执行函数
{
cout << "Run lua Function Error!" << endl;
const char *tempstr = lua_tostring(L, -1);
cout << tempstr << endl;
}
lua_close(L);
}
编译链接:g++ main.cpp -llua -ldl
Lua中使用C/C++模块
一般采用动态链接库的方式载入模块,所以首先要先编译C/C++文件,生成动态链接库
头文件:
#ifndef _CPPLUALIB_H
#define _CPPLUALIB_H
#ifdef __cplusplus
//以下内容按C的规则进行编译
extern "C"{
#endif
/必须在h文件中加入这几个头文件,否则认不到LUA_API/
/防止重复定义,可以自己宏定义个flag/
#include"lua.h"
#include"lualib.h"
#include "lauxlib.h"
LUA_API int luaopen_my_lib(lua_State *L);
#ifdef __cplusplus
}
#endif
#endif
C++文件:
#include<iostream>
#include<stdio.h>
#include<string>
#include "cpplualib.h"
using namespace std;
static int SayHello(lua_State *L)
{
cout << "Hello World!" << endl;
int num = lua_gettop(L);
cout << num << endl;
// cout << temstr << endl;//所有参数都被放入L栈中
//lua_pushstring(L, "LZ");
return num;//返回所有压栈数量
}
static const struct luaL_Reg my_lib[] =
{
{"SayHello", SayHello},
{NULL, NULL}
};
int luaopen_my_lib(lua_State *L) //必须和上面的数组同名,并且生成的动态链接库也必须命名为my_lib.so
{
luaL_newlib(L, my_lib);
return 1;
}
Lua文件:
local mylib = require "my_lib"//导入模块
print (mylib.SayHello("mytest", 1,2,3))
生成动态链接库:g++ -fPIC -shared -o my_lib.so xxx.cpp
执行Lua脚本:lua xxx.lua即可看到打印输出
语法糖
1、
t_table = {}
t_table["li"] = "lizhong" --等价于t_table.li = "lizhong"
2、
t_table = {'a', 'b', 'c', key1 = 'cc', 'bb'}
for i = 1, #t_table do --#t获取table中key为数字的个数,key为nil的元素则不统计。table.maxn则以最大数字下角标为准,统计nil
print(t_table[i]) --输出a, b, c, bb
end
3、
必用脚本语法
1、脚本开头可加#!/usr/local/bin/lua用于指定解释器路径,可不用显式使用lua。(实际测试结果:还是需要显式使用lua xxx.lua才能执行)
2、单行注释:– //两个减号
多行注释:–[[xxxxxxxxx –]]
3、标识符(变量名):不要使用下划线加大写字母的标识符,因为lua中的保留字一般这样写。约定下划线开头连接一串大写字母的名字(_VERSION)被保留用于lua内部全局变量。lua区分大小写
4、全局变量:默认情况下,变量总是全局的,给一个变量赋值后即创建了这个全局变量,访问一个没初始化的全局变量会返回nil,若希望删除一个全局变量,只需要将变量赋值为nil(也就是说,当且仅当一个变量不等于nil时,这个变量即存在)
数据类型
脚本语言无需定义变量类型,只需要对变量进行赋值
nil:表示一个无效值(具有删除作用,给一个)
boolean:false和true
number:表示双精度类型的实浮点数(可以看出lua中的数值都按此类表示)
string:字符串由一对双引号或单引号来表示
string1 = 'hello'
string2 = "hello"
string3 = [[123,
456
78965413
]] --[[]]可表示一块字符串
print('2'+6) --return 8.0,lua会自动将数字字符串转换为一个10进制数字,直接丢弃其引号
print(#'132123') --用#计算字符串长度
function:由C或lua编写的函数
function test(n)
print(n)
test1 = test
test1(10) --lua中函数可以直接赋值给变量,通过变量调用此函数
function printf(n,fun)
fun(n)
printf(1, function(m)
print(m)
end) --function定义一个匿名函数
userdata:表示任意存储在变量中的C数据结构,可以将C/C++中的任意数据类型(通常是struct和指针)存储到lua变量中调用
thread:表示执行的独立线路,用于执行协同程序
table:一个关联数组,用{}来创建。(可以看出table类似于Python中的字典,只不过此处更适合看做是变量和其值的集合)
key的几种类型:
dir0 = {["key1"] = 1, key2 = 2} --等价,key定义时若为数字或字符串则需加[]
dir1 = {key1 = 'value1', key2 = 'value2'} --需要使用dir1["key1"]进行索引
dir2 = {'value1', 'value2'} --一维数组 --等价于:dir2 = {[1] = 'value1', [2] = 'value2'}
-需要使用dir2[1]和dir[2]进行索引,注意lua中下标是从1开始计数的,而非0
dir3 = {i = 'a', 'b', 'c', ii = 'd', 'e'} -- dir3[3]返回e
可以使用type函数查询类型:
print(type(“123”)) –>string
print(type(123)) –>number
do end –相当于C++中的{}名称空间
lua变量
局部变量的作用域仅限于声明他们的那个块。块可以是一个控制结构的执行体、一个函数的执行体或者是一个程序块(do end中间的部分)
(所声明的局部变量的作用域从声明语句开始,直至所在块的结尾)
x = 10 --没有local就默认为全局变量,在函数中也是如此
local i = 1 --程序块中的局部变量
while i <= x do
local x = i * 2 --while循环体中的局部变量
print(x) --while循环体中的局部变量,输出2,4,6,8…
i = i +1
end
if i > 20 then
local x --then中的局部变量
x = 20 --then中的局部变量
print(x + 2) --then中的局部变量,输出22
else
print(x) --开头定义的全局变量x,输出10
end
print(x) --开头定义的全局变量x,输出10
注意:交互模式下每输入一行语句都会成为一个程序块,所以想在交互模式下正确指定作用域,就需要显示的用do end来指定块
关系操作符
只能对两个数字或两个字符串做大小比较,不同类的会返回false。字符串的比较是按照字母次序例如:
"bc" < "ace" -->返回false
"2" < "15" -->返回false
"a" > "9" -->返回true,说明字母字符串总大于数字字符串
nil只与其自身相等
~= –不等
= –赋值,注意table的赋值是引用(不同于深浅拷贝)
a = {'a', 'b'}
c = a
c[1] = 'z'
print(a[1]) -->返回z,说明是引用
c = {'v', 'r'}
print(a[1]) –>返回z,说明c已经变为了另一个table的引用
逻辑运算符
not 数字 –>输出都为false
not nil –>输出true
not false –>输出true
(a > b) and a or b –>a若大于b则括号内成立,则true and a or b,根据短路法则直接返回true and a。(and对应&&,or对应||),有nil参与的逻辑运算可将nil视为0
字符串连接符
..(两个点),如果任意一边是数字则会将数字直接转换为字符串(直接加引号)再进行连接输出。
运算符优先级
由高到低(高优先级先执行):
^(右结合:x^y^z <--> x^(y^z))
not # -
* / %
+ -
..(右结合)
< > <= >= -= ==
and
or
多重赋值
交换:x, y = y, x –x与y互换
右边值多于左边变量,值会被丢弃。右边值少于左边变量,多出的变量被置为nil
控制结构
注意:在控制结构中所有不是false和nil的值都会被视为真(数字0也是真)
if ... then
...
else
...
end
if … then
…
elseif … then
…
else
…
end
whie … do
…
end
repeat --重复执行循环体,直到条件为真
…
until …(条件)
–数值for循环
–var从exp1变化到exp2,每次变化以exp3为步长递增,并执行一次循环体,若不存在exp3,则默认步长为1。for的三个表达式在循环开始前进行一次性求值,之后不再求值
for var = exp1, exp2, exp3 do
<执行体>
end
–泛型for循环(注意pairs是无序的,ipairs是有序的)
dir3 = {i = 'a', 'b', 'c', ii = 'd', 'e'}
–pairs(dir3)方法可以用于遍历table,可以遍历表中所有的key。
–ipairs(dir3)只能遍历到表中出现第一个不是整数的key。也就是说ipairs(dir3)只可以遍历出b,c,e
dir3 = {[2] = 'b', 'c', 'e'}–这样ipairs将遍历出c,e。因为[2]的值再e定义时被改写了
dir3 = {key1 = 'a', key2 = 'b'}–这样ipairs将无法遍历,直接跳出循环,因为dir3[1]=nil
–pairs和ipairs只能遍历一维数据,多维数据还是要依赖for循环
多重返回函数
function foo()
return 'a', 'b'
end
function goo(i, j, k)
return i, j, k
end
–若foo()被调用,并且不是一系列表达式的最后一个元素,那么Lua会将其返回值数量调整为1
x, y = foo(), 10 --x = 'a', y = 10
print(foo(), 2) --输出a, 2
goo(foo()) --输出a, b, nil
goo(foo(), 1) --foo将只返回一个值,输出a, 1, nil
goo((foo())) --foo()放入括号内将迫使它只返回一个值a, nil, nil
–泛型调用,unpack(),接受一个数组table作为参数,并从下标1开始返回该数组的所有元素,与ipairs相似,只不过这个可以直接返回值
list1 = {'a', 'b', 'c'}
print(table.unpack(list1))
–变长参数
function add(…)
local s = 0
for i, v in ipairs(…) do
s = s + v
end
return s
end
print(add({10, 20, 30, 40})) --返回100,注意…处需要传入的是一个table
function foo(…)
local a, b, c, e, f =…
end
function goo(a, …) – 在变长参数…前可以加入固定参数
print(a, …) --注意…处需要传入table,零散的参数不可以
end