• Lua知识备忘录


        最近对Lua很感兴趣,以下是本阶段学习的总结,包含三部分,一部分是基础语法,一部分是扩展和解释器嵌入,最后一部分是Lua小练习。

       知识涉及:Lua语言编程基础;Lua&C++:Lua扩展、嵌入Lua解释器、裸写C++扩展、借助swig写C++扩展。平台:Linux、gcc4.8.2

    一、基础语法

    1、print("Hello World")

    Lua中不需要分号,也不需要python那样的严格格式;

    单引号跟双引号等价,多行文本使用两个中括号扩起来:[[multi line]];

    代码中的注释:--开头的一行,或者是--[[ 多行注释 --]];

    Lua关键字:and break do else elseif end false for function if in local nil not or repeat return then true until while;

    所有变量默认是全局变量,除非加上local 关键字;

    支持多参数赋值:a, b = 1, 2;

    Lua中的变量是对值的引用;

    and和or都是short-cut-evaluation,a = 4 and 5, a是5; a = 4 or 5,a是4;

    Lua不支持:switch-case、continue、i++、++i;

    Lua将false、nil视为假,将其它视为真;

    在Lua5.2之后,全局表为_ENV是一个table,这里包含了所有能使用的函数、类型、全局变量;

    package.loaded 这也是个table,保存了所有加载的模块,如果写扩展(Lua脚本或者C模块),可以通过修改_ENV表或者package.loaded来手动添加扩展模块;

    2、数据类型

    (1)常用数据类型:number、string、table、function、bool、nil;
    (2)不常用数据类型:userdata、thread;

    注意:table也就是key--value键值对;function也是一种类型;thread也是一种类型,与协程相关;userdata用于表示自定义类型。

    3、连接字符串

     a..b,变量a跟变量b的值连在一起,a和b是number或者string;

    eg: 

    a = 123  b = 'world' print(a..b)  --输出:123world

    4、table变量的定义

    (1)a = {}   变量a指向空的table

    (2)a = {1, "2"}    变量a指向 {1, "2"} table

    (3)a = {} a["a"] = 1 a["x"] = 2    变量a指向空的table,接着通过a对这个table赋值

    (4)a = {["x"] = 1, y = 2, [1] = "a"}    table构造的方式1

    (5) a = {[{}] = "x", b = {}}   table构造的方式2

    table可以作为数组,如上面的(2),也可以是map,如上面的(3)和(4)。

    key可以是任何数据类型:number、string、table、function,value也可以是任何数据类型。
    这也许就是动态类型带来的极大随意性吧。

    5、table变量的使用

    a[1] 或者是 a["b"],总之就是用map的方式去索引,table也用来表示数组(数组也只能用table表示),数组table的key为数字。

    6、获取数组的长度

    (1)如果是纯粹的数组(索引只有数字),则可以:#arrary、table.maxn(array),
    #array只能获取到连续的序号;
    table.maxn(array)则是获取到最大的序号;
    如:a = {'a', 'b', [1000]='z'}
    #a 输出2
    table.maxn(a) 输出1000
     
    (2)不纯粹的数组
    如果是包含有非数字序号的,则上述两个方法都无法获取到数组长度,唯一的方法是遍历所有的元素
    如:
    function tablelength(T)
        local count =0
        for _ in pairs(T) do 
            count = count +1
        end
        return count
    end
    可参考:

    7、if--else语句

    a = 1
    if a == 1 then
        print("a is 1")
    elseif a == 2 then
        print('a is 2')
    end
    -- 不等于号:~=

    8、while语句

    a = 1
    while a ~= 5 do
        a = a + 1
        print(a)
    end

    注意:没有continue、i++

    9、for语句

    for语句有两种使用方式:
    (1) for 开始数字、终止数字、步长 do ...
    for k = 1, 10, 2 do 
        print(k) 
    end -- 输出:1 3 5 7 9

    (2) pair 和 ipair

    a = {'a', 'b', 'c'}
    for k, v in ipairs(a) do 
        print(k, v)
    end  
    --[[
    输出:
    1    a
    2    b
    3    c
    --]]
    
    a = {b='b', a='a'}
    for k, v in pairs(a) do 
        print(k, v)
    end
    --[[
    输出:
    a   a
    b   b
    --]]

    ipair只能用在数字为key的table上,且遍历从1开始,直到对应key的value为nil,pair则没有这个限制。

    10、repeat语句

    a = 1
    repeat 
        a = a + 1
        print(a)
    until a == 5

    11、函数

    function add(a, b)
        return a + b
    end
    function nothing(a, b)
        return a, b
    end

    括号不能随便加,多个返回值再加上括号,就只返回一个:

    print(nothing(1, 2)):   --输出1 2
    print((nothing(1, 2))):  -- 输出1 

    如果参数是一个table,则可以省略括号:

    function add(a)
        return a.a + a.b
    end
    
    print(add({a = 1, b = 2}))  -- 3
    print(add{a = 1, b = 2})  --3

    支持可变参数:

    function test1( ... )
        for i = 1, select('#', ...) do
            local arg = select(i, ...)
            print(arg)
       end
    end
    
    
    function test2( ... )-- 这种方式不推荐,会导致nil参数把参数列表截断
         for i, v in ipairs{...} do
             print(v)
         end
    end
    
    
    test1('a', nil, 'c')
    --[[
    输出:
    a
    nil
    c
    --]]
    
    test2('a', nil, 'c') 
    --[[
    输出:
    a
    --]]

    12、闭包(closure)

    闭包对于C++程序员来说是个新奇的概念(三年前我就觉得它很新奇),举个栗子:

    test = function(a)
        first = 2;  --这个变量可以被嵌套在test函数中的函数访问,这个在Lua中也称为upvalue
        return function(b) 
            tmp, first = first, b
            return tmp + b end
    end
    
    add = test();
    print(add(2)); -- 4
    print(add(3)); -- 5

    闭包也是实现泛型for的原理(就是有个地方保存着变量),闭包还可以实现私有变量。 

    15、require引入扩展库

    require('math') 
    print(math.pi)

    16、IO操作

    --读文件:
    local file = assert(io.open('file_path', 'r'))
    for line in file:lines() do print(line)
    end
    file:close()
    --写文件:
    f_w = assert(io.open('file_path', 'w'))
    f_w:write('xxx')
    f_w:close()

    17、table库,可以对数组做各种操作

    注意,是数组。
    (1)数组元素连接:table.concat, : a = {"a", "b"} print(table.concat(a)) 输出:ab
    (2)数组元素插入: table.insert, : a = {"a", "b"} table.insert("c")
    (3)数组元素最大序号:table.maxn, : a = {"a", "b", [100] = "z"} print(table.maxn(a))
    (4)数组元素删除:table.remove, : a = {"a", "b"} table.remove(a, 1): 删除到序号为1的元素“a”
    (5)数组元素排序:table.sort, :默认会根据元素的值从小到大排序,也可以自定义排序lambda函数:

    a = {"b", "1", "z", "a"} 
    table.sort(a, function(a, b) return a > b end)
    print(table.concat(a))

    18、string库可以对数组做各种操作,有类正则表达式的功能

    string.gfind string.gmatch string.gsub string.len

    eg:

    a = 'abc123'
    b = string.match(a, '[a-z]([a-z])')
    print(b)  --输出:b
    
    b = string.gmatch(a, '[a-z]')
    for item in b do print(item) end  --输出:a b c
    
    local _, count = string.gsub(a, "[a-z]", "X")
    print(_) -- 输出:XXX123
    print(count) --输出:3
    
    print(string.len(a)) --输出:7

    19、协同程序

        这是个有趣的功能,简单说就是让一个函数执行到一半就停下来去干别的,接着由于某些事件触发它继续往下走。控制者和被控制者在同一线程中执行,所以协程是单个线程上的设计,设计的初衷可能是为了在执行IO操作时交出控制权,之后再通过状态切换/事件通知的方式让程序继续往下执行,减少CPU的空闲等待浪费。
    lua上的demo:

    co = coroutine.create(function() print("hi") end)
    coroutine.resume(co)

        协程这个知识很多语言都有,甚至在Linux C++中,都有人为网络服务实现了协程,做法是对阻塞的socket API做hook,调用这个函数时,应用程序切换去做其它事情,直到有通知触发,才继续从阻塞处往下执行。
    扩展阅读:http://www.udpwork.com/item/12045.html;腾讯开源的libco库:http://code.tencent.com/libco.html

        协程的关键是,在执行耗时IO操作时,系统可以让出控制权,让用户去干别的事情。这跟异步API很像,不同的是异步API的使用会要求有回调函数,所以我们实现一个功能的时候,会有异步API调用+回调函数,这样就有两部分代码(当然,有些语言可以有lambda函数,这样代码就放在一块了),而如果使用协程,代码是可以放在一起的,好像在使用同步API写代码一样(调用到关键API时会主动停下来,交出控制权,后面能拿到控制权继续往下执行)。
    扩展阅读:http://blog.csdn.net/kobejayandy/article/details/11856735

        在Lua中,通过协程可以实现主程跟协程的数据交换:

    在协程函数中有这样的语句:a = coroutine.yield(xxx);在主程序中通过 coroutine.resume(co, yyy);  激活协程函数;主程序调用者,将得到xxx,而被调用者拿到的a是resume的参数yyy。所以,resume和yield配合:resume可以在主程序中将外部数据传递给协程内部;yield则将内部数据传递给主程序,eg:
    function foo (a)
        for i=1, 10 do
            print('I get from outsite:'..coroutine.yield('I sent to outsite:'..(2 * a)))
        end
    end
    
    co = coroutine.create(foo)
    print(coroutine.resume(co, 1))
    
    --[[ 输出:
    I get from outsite:1
    true    I sent to outsite:2
    --]]

    20、Lua的扩展模块加载路径

    require('xxx'),可以加载xxx扩展模块,如果require找不到Lua文件就会去找C程序库,Lua文件跟C程序库是两种可能的Lua扩展方式。

    在Lua解释器中执行下面两个语句:

    print(package.path) --这是Lua脚本模块可加载地址
    print(package.cpath) --这是C程序库可加载地址

    Lua脚本模块加载路径格式举例:.?.lua;C:Program Files (x86)Lua5.1lua?.lua;  其中?是通配符,表示任意名字。

    Lua扩展C程序库加载路径格式举例:.?.dll;.?51.dll; 如果在Linux下这是?.so.

    在Linux下可以通过修改设置LUA_PATH、CLUA_PATH两环境变量来设置对应的加载路径,eg:

    export LUA_PATH='/home/work/cswuyg/install/lua-lua/lib/md5/?.lua;./?.lua'
    export LUA_CPATH='/home/work/cswuyg/install/lua-so/?.so;./?.so'

    21、元表和元方法

    对象可以指定元表,元表里包含有元方法,元方法可以做很多高级的事情。

    print(xx.yy),如果xx变量没有yy字段,那么就会去查找xx是否有元表,如果xx有元表,就去查xx的元表中是否有__index元方法,如果有元方法,就从元方法中获取yy字段的值。

    __index 元方法用于读取,eg:
    mt = {}  -- 元表
    a = {}
    setmetatable(a, mt)
    mt.__index = {['x']=1}
    print(a.x) 
    -- 输出:1
    而__newindex用于赋值,例如:
    mt = {}
    mt.__newindex = {}
    a = {}
    setmetatable(a, mt)
    a.x = 10
    for k, v in pairs(mt.__newindex) do
    print(k, v)
    end
     --[[
    输出:
    x       10
    注意到,x并没有保存在a中,而是保存在a的元表的__newindex字段所指向的table里。
    --]]
    如果想要不经过__index、也不想经过__newindex保存数据,那么可以采用原始的方法访问:
    rawget(table, index),
    eg:
    a = {['a'] = 'xx'}
    print(rawget(a, 'a')) --输出xx

    使用元表.__index元方法设置元素的默认值

    --设置table的默认值:
    function set_defalut(table, value)
        local key = {}
        table[key] = value
        local mt = {__index = function(table) return table[key] end}
        setmetatable(table, mt)
    end
    
    table = {}
    set_defalut(table, 100)
    print(table.x) --输出100
    
    --当table中不存在x时,会去找__index字段保存的函数。
    “重载”tostring元方法:
    function to_string(a)
        local ret = ''
        for k, v in pairs(a) do
            ret = ret..k..':'..v..'
    '
        end
        return ret
    end
     
    function add_to_string(a)
    mt = {__tostring=to_string}
    setmetatable(a, mt)
    end
     
    table = {['a'] = 'a', ['b'] = 'b'}
    add_to_string(table)
    print(table)
    
    --[[输出:
    a:a
    b:b
    --]]

    22、点号跟冒号的区别

    定义function的时候,如果使用冒号,那么默认会有self参数,self指向调用者自身;
    调用function时,要采用冒号调用,如果采用点号调用,则要显式的指明self。
    A = {["b"]="b"}
    function A:next(info)
        print(info, self.b)
    end
     
    function A:first(x)
        A:next("call from A:first")
    end
     
    A:first('x')
    --[[
    输出:call from A:first       b
    --]]

    23、Lua匹配UTF8汉字

    demo: head = string.match(line, '([%z1-127194-244][128-191]*).*')   

    %z表示0,

    %z1-127194-244][128-191]* 这是一个汉字的UTF8正则表示,

    整个句子是用于获取line的第一个汉字。

    二、扩展&C++

    1、使用Lua语言写Lua扩展模块,实现两个数组的并集,并能序列化输出

    模块的实现:mod.lua

    module(..., package.seeall)
    
    function union(t1, t2)
        local ret = {}
        for k, v in pairs(t1) do
            ret[v] = true
        end
        for k, v in pairs(t2) do
            ret[v] = true
        end
        mt = {__tostring=__tostring}
        setmetatable(ret, mt)
    
        return ret
    end
    
    function __tostring(t) 
        ret = ''
        for k, v in pairs(t) do
            ret = ret..k..'
    ' 
        end
        return ret
    end

    模块的使用 user.lua:

    require('mod')
    
    t1 = {'a', 'b'}
    t2 = {'b', 'c'}
    
    print(mod.union(t1, t2))
    
    --[[
    输出:
    a
    b
    c
    ----]]

     上面模块的代码,涉及到的知识:扩展模块编写、元表元方法、table遍历、字符串连接

    2、嵌入Lua解释器

    Lua语言天生是为嵌入存在,嵌入也是很简单的事情。

    让你的可执行程序能够执行Lua脚本代码,举个栗子:

    下载:首先要到官网下载Lua源码:http://www.lua.org/download.html,我下载了最新的Lua-5.3.2版本。

    编译:如果Linux环境下出现错误:libreadline.so: undefined reference to `PC,需要修改、src/Makefile,增加-lncurses;可能还需要修改Makefile里的安装目录,装到自己目录下。

    然后就可以开始写测试代码了:

    makefile:

    OBJ=test.o
    CC=g++
    CFLAGS=
    ROOTDIR=./../
    LUADIR=/home/users/cswuyg/install/lua/
    LIBS=-llua -ldl
    
    test: $(OBJ)
        $(CC) $(CFLAGS) -o test $(OBJ) -L$(LUADIR)lib $(LIBS)
    
    test.o: test.cpp
        $(CC) $(CFLAGS) -c test.cpp -I$(LUADIR)include

    test.cpp

    /**
     * @file test.cpp
     * @author cswuyg
     * @date 2015/12/20 12:44:38
     * @brief 嵌入Lua解释器
     *  
     **/
    extern "C"
    {
        #include "lua.h"
        #include "lualib.h"
        #include "lauxlib.h"
    }
    #include <iostream>
    #include <string>
    #include <iostream>
    #include <string>
    #include <fstream>
    #include <sstream>
    
    //测试 luaL_dofile函数
    void test_dofile(lua_State* L, const std::string& file_path) {
        luaL_dofile(L, "test.lua");
        std::string lua_ret = lua_tostring(L, 1);
        std::cout << "lua ret:" << lua_ret << std::endl;
    }
    
    //测试 luaL_dostring函数
    void test_dostring(lua_State* L, const std::string& file_path) {
        std::ifstream ifs;    
        ifs.open(file_path.c_str());
        if (!ifs.is_open()) {
            return ;
        }
        std::stringstream buffer;
        buffer << ifs.rdbuf();
        std::string file_info(buffer.str());
        luaL_dostring(L, file_info.c_str());
        std::string lua_ret = lua_tostring(L, 1);
        std::cout << "lua ret:" << lua_ret << std::endl;
    }
    
    int main(int argc, char* argv[]) {
        lua_State* L = luaL_newstate();
        luaL_openlibs(L);
        test_dostring(L, "test.lua");
        test_dofile(L, "test.lua");
        lua_close(L);
        return 0;
    }

    test.lua

    function add(a, b)
        return a + b
    end
    
    c = add(10, 20)
    return "10 + 20 is: "..c

    从上面的test.cpp demo中可以看到关键函数:luaL_dostring 或者 luaL_dofile。

    嵌入Lua解释器之后产生的ELF文件,strip(Linux strip命令)之后只有204KB。

    Lua解释器的效率非常高,对于hello world类的demo,只需要200微秒(在我的机器上),而对应的采用V8解释器执行js hello world需要2毫秒。

    对于存在大量重复调用的demo代码,上了LuaJIT性能可以提高几倍(如果代码不存在多次调用,JIT很难提高性能,除非是运行时的其它处理能达到代码优化效果。测试了一次lua add函数调用,LuaJIT性能没有提高)。以下是多次重复Lua函数调用测试代码:

    function add(a, b)
        return a + b 
    end
     
    for k = 1, 100000 do
    c = add(10, k)
    end
    return "10 + 20 is: "..c       

    Lua耗时:10700微秒;

    LuaJIT耗时:617微秒;

    LuaJIT对于热点代码能极大提高运行效率,因为这些热点代码被执行后,会被以机器码的形式保存,后续的多次调用不需要再走转换流程,直接执行机器码,性能提高许多。

    JIT结合了静态编译和动态解析的好处,在执行动态语言时,会将翻译过的代码以机器码缓存起来,后续的使用就不需要再次翻译,更多参考JIT知识:https://en.wikipedia.org/wiki/Just-in-time_compilation

    如果要使用LuaJIT,源码下载地址:http://luajit.org/download.html,我上面测试使用的是LuaJIT-2.0.4;使用方式跟非JIT Lua方式一致,使用JIT的ELF文件比非JIT的大200KB。

    3、使用C++语言写Lua扩展模块

    以下内容可能会比较碎,解决问题的方法不是不唯一的。

    Lua调用C++函数,或者C++函数调用Lua,最重要的技术点就是两种语言的‘沟通’,Lua的C++语言跟Lua语言数据交互是通过一个叫做Lua 状态机(lua_State)的东西来做的,可以把它看作一个‘栈’。

    我在练习写扩展模块的时候,基本按照这样的层次来写:实现层、包装层、注册层。这对业务功能做了划分,也对脚本语言层面的扩展做了划分,后续有新业务功能开发,或者新脚本语言扩展,已经有的业务功能实现不需要改动。

    在用C++为Lua写扩展时,有两种使用方式,一种是提供一个so,Lua程序去require后使用,另一种是我写的扩展类型可以跟Lua的内置类型一样使用。我做了第二种实现的demo,如果要修改为使用so导出,只要增加一个生成so的makefile就可以。

    C++写扩展的demo代码见github:自定义C++类加入Lua注:这个例子是将Lua解释器嵌入到应用程序中,由我的应用程序去执行Lua脚本代码。

    至少有两种方式可以将自定义函数/类型加入到全局表中,

    方式1:

    //把lib->func执行的结果作为lib->name的value保存到package.loaded 中      
    luaL_requiref(L, lib->name, lib->func, 1); 
    //清空状态机L
    lua_settop(L, 0);

    方式2:

    lib->func(L);//执行注册,L栈顶是注册了函数的table             
    lua_setglobal(L, lib->name);  //把栈顶的table作为value,以lib->name 作为key保存到全局表中。

    详细代码见这里

    这两种方式可以实现把导出函数table放到全局表/已加载包中,使用者直接 {require("name")},就可以使用 name.xxx,而不需要 {name = require("name")};用起来跟文章上边的mod.lua 模块一样。
    如果不是直接把table放到全局table或者包加载table中,那就是这样子写:lua-socket.c,只使用luaL_newlib API把函数table设置到状态机的栈顶。

    在编写Lua扩展时,如果有需要在扩展模块中保存数据状态,可以使用1、全局数据状态,关键字:LUA_REGISTRYINDEX;2、模块环境,关键字:LUA_ENVIRONINDEX;3、闭包函数,关键字:lua_pushcclosure;学习资料:http://www.cnblogs.com/stephen-liu74/archive/2012/07/25/2470025.html

    4、借助swig框架实现Lua扩展模块

    swig:http://nchc.dl.sourceforge.net/project/swig/swig/swig-3.0.7/swig-3.0.7.tar.gz,下载之后配置--prefix,做编译安装即可。

    文档:http://www.swig.org/Doc2.0/Lua.html

    以下为demo,由两部分组成:我们的实现代码;xxx.i文件,用于给swig生成框架。

    my_module.i (生成wrapper文档命令行:swig -c++ -lua my_module.i)

    %module my_module 
    %include "std_string.i" 
    %{
    #include "my_module.h"
    %}
    %include "my_module.h"

    注意到上面的std_string.i,必须有它才能导出std::string类型,更多的其它类型在这里swig的github

    my_module.h

    /**
     * @file my_module.h
     * @author cswuyg
     * @date 2015/12/20 18:05:05
     * @brief 我的测试模块
     *  
     **/
    #ifndef  __MY_MODULE_H_
    #define  __MY_MODULE_H_
    
    #include <string>
    
    int add(int a, int b);
    
    class Hello {
    public:
        std::string get_info();
        bool set_test(Hello* p);
        Hello* get_test();
    private:
        Hello* _test_p;
    };
    
    
    #endif  //__MY_MODULE_H_
    
    /* vim: set expandtab ts=4 sw=4 sts=4 tw=100: */

    test.lua

    a = my_module.Hello()
    b = my_module.Hello()
    a:set_test(b);
    c = a:get_test();
    print(c:get_info());
    
    print(my_module.add(1, 2))

    完整代码见github:利用swig做封装注:这个例子是将Lua解释器嵌入到应用程序中,由我的应用程序去执行Lua脚本代码。

    使用swig框架可以让开发者把精力放在业务层面,省力不少,除了swig,还有Luabind、LuaPlus...等一堆框架/工具。我选择swig做,是因为swig也支持Python、JavaScript...

    三、Lua练手

    1、遍历成语词典,获取某个字开头的成语,用到了MongoDB第三方lua驱动,它的代码很简短,文章最后有介绍。

    --[[
    生成某个字开头的所有成语
    cswuyg 2015.12.1
    思路:
    1、先在外面把成语词典转换为UTF8格式;
    2、使用正则表达式剔除非四字成语;
    3、使用正则找出四字成语的首字
    ----]]
    require('math')
    mongo = require "mongo"
    
    client = mongo.client{ host = 'xxxx host', port='27017' }
    insert_to_mongo = function(t) --这里是单条写入,批量写入会快点,但mongo驱动在批量写入时有core,暂不使用批量
        client.idioms_solitaire_dataxx.head:insert(t)
        local r = client:runCommand('getLastError', 1, 'w', 1)
    end
    
    -- 操作控制
    idioms_ctrl = {
        idioms_path = nil , -- 成语词典路径
        idioms = {}, -- 内存成语词典
        idioms_len = 0, -- 成语词典长度
        head_table = {}
    }
    
    --建立head 词典
    function idioms_ctrl:build_head_dict()
        self.head_table = {}
        for k, v in ipairs(self.idioms) do
            head = string.match(v, '([%z1-127194-244][128-191]*).*')
            if self.head_table[head] then 
                table.insert(self.head_table[head], v)
            else
                self.head_table[head] = {v}
            end
        end
    end
    
    -- 加载字典到idioms中,并创建head_dict
    function idioms_ctrl:load_dict()
        local file = assert(io.open(self.idioms_path, 'r'))
        for line in file:lines() do
            local idiom = {}
            local_, count = string.gsub(line, "[^128-193]", "")  --统计有多少汉字
            if count == 4 then --只保留4字成语
                for uchar in string.gmatch(line, "[%z1-127194-244][128-191]*") do 
                    table.insert(idiom, uchar)
                end
                item = table.concat(idiom)
                if string.len(item) > 0 then
                    table.insert(self.idioms, table.concat(idiom))
                    self.idioms_len = self.idioms_len + 1
                end
            end
        end
        idioms_ctrl:build_head_dict()
    end
    
    -- 写到mongodb和文件
    function idioms_ctrl:write_all_head()
        self.f_w = assert(io.open(self.result_path, 'w'))
        for head, idioms in pairs(self.head_table) do
            idioms_ctrl:write_result(head, idioms)
        end
    end
    
    -- 写入结果到结果文件
    function idioms_ctrl:write_result(head, list)
        self.f_w:write(head..':'..table.concat(list, ',')..'  len:'..#list..'
    ')
        info = table.concat(list, ',')
        xx = {['_id']=head, ['data']=info, ['len']=#list}
        insert_to_mongo(xx)
        return false
    end
    
    -- 全部跑
    function run(idioms_dict_path, result_path)
        print('dict :'..idioms_dict_path)
        idioms_ctrl.result_path = result_path
        idioms_ctrl.idioms_path = idioms_dict_path
        idioms_ctrl:load_dict()
        idioms_ctrl:write_all_head()
    end
    
    -- 主函数
    function main() 
        math.randomseed( tonumber(tostring(os.time()):reverse():sub(1,6)) )
    
        local s = os.clock()
        if not arg[1] or not arg[2] then
            print('input format: lua xx.lua [idioms_dict_path] [result_path]')
            return false
        end
        print('arg[1]:'..arg[1])
        print('arg[2]:'..arg[2])
        run(arg[1], arg[2])
        local e = os.clock()
        print('cost second:'..e-s)
    end
    
    main()

    补充:

    1、Lua5.1版本的string.gfind,在5.2版本中更换为string.gmatch.

    2、luaL_register函数可以将C函数注册到Lua语言环境的package.loaded中,这个函数在Lua5.2中被废弃,不再支持直接注册到全局表中,一般更换为使用:luaL_newlib,将函数注册到堆栈顶的table,然后再另行处理(如使用lua_setglobal)。

    3、Lua的MD5库,到github上找一个,然后设置到LUA_PATH上即可,用过的MD5库:https://github.com/kikito/md5.lua

    后续工作重点已经不在Lua上,但会不定期更新。

    本文所在:http://www.cnblogs.com/cswuyg/p/5049935.html 

    学习资料推荐:

    1、《Lua程序设计》

    2、http://www.jellythink.com/archives/category/language/lua

    3、http://www.lua.org/manual/5.2/manual.html 

    4、云风的MongoDB Lua驱动,代码精致可读:https://github.com/cloudwu/lua-mongo/,编译时需要Lua5.2版本,可能需要修改makefile文件

  • 相关阅读:
    4.父类私有属性和方法
    3.单继承和方法的重写
    2.Python封装练习及私有属性
    1.Python面向对象基础
    6.类与对象、封装、构造方法
    5.数组
    4.方法
    3.流程控制语句
    结构型模式和物理视图,模型管理试图的总结
    创建型模式和关于状态视图、活动视图、交互视图的总结
  • 原文地址:https://www.cnblogs.com/cswuyg/p/5049935.html
Copyright © 2020-2023  润新知