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