之前因为工作的需要学习了lua,在使用的过程中发现Lua挺好用的,故决定把这门语言好好学习一下。这段时间一直在学习Lua,也一直在使用Lua,但是因为工作忙的关系,都没有时间把这些学习的心得记录下来。趁着现在国庆放假期间,把上个月的学习心得记录一下,方便自己后续的查找与回顾(谁叫自己的记忆力已经大不如前了,有些知识长时间不用,就会生疏了)。
好了,废话不多说,总结的内容大致有如下方面:
1) lua package的编写,会以自己编写的简单的loger模块为例进行介绍;
2) 在lua package的基础上,简单分析一下luabit模块的源码;
3) 用c对lua进行扩展;
4) 简单分析一下lua_epoll模块;
5) userdata
6) 在userdata的基础上,实现一个简单的buffer模块;
7) coroutine
一、 lua package
在开发中,我们经常都会根据功能进行模块划分,然后把该模块提供的方法放在对应的文件中。
lua package 可以简单的认为就是一个“库”,对外提供相应的功能方法。
在lua中,每一个package都有自己的命名空间,避免了命名冲突。
通常,一个简单的package如下所示:
#mymodule.lua module(..., package.seell) -- ...表示用当前的文件名作为package名 local function no_access() -- private function print ‘can not access into this function!‘ end function hello() -- public function return ‘hello to mymodule‘ end return _M
使用mymodule.lua。先来看一下但我们require mymodule模块后,lua会将其加入到_G table中,看一下都有什么内容:
# using mymodule require(‘mymodule‘) -- 相当于C语言中的include,或者是Python中的import for k, v in pairs(_G.mymoudle) do print(k, v) end
输出结果如下:
hello function: 003CBFB0
_M table: 003CBB88
_NAME mymodule
_PACKAGE
可以看到模块中只有hello函数,那么no_access函数呢?因为我们在定义no_access函数时,前面加上了local,就相当于这个函数是模块内部的,对外不可见,有点和C中的static类似。
从上路可以看出编写一个package,以及使用package都是比较简单的,并没有什么特别的复杂语法要求。
二、 简单的loger模块;
我们在c语言开发的时候,经常会在log输出的时候,加行当前所在的函数与行号,如printf("%s()-%d: %s", __func__, __LINE__, "debug info");
我在lua调试中,希望可以在log输出时,自动输出当前的函数名与行号,所以就写了个简答的loger模块,支持定义log级别并进行输出过滤。如有需要可进行改写,将log输出到文件中。
loger模块中使用了debug.getinfo()方法,如要获取所有的信息,则使用debug.getinfo(3)
代码如下:
module(..., package.seeall) --local fd_buf = require(‘fd_buffer‘) local function show_debug_info(info) print(‘source:‘, info.source) print(‘what:‘, info.what) print(‘func:‘, info.func) print(‘nups:‘, info.nups) print(‘short_src:‘, info.short_src) print(‘name:‘, info.name) print(‘currentline:‘, info.currentline) print(‘namewhat:‘, info.namewhat) print(‘linedefined:‘, info.linedefined) print(‘lastlinedefined:‘, info.lastlinedefined) end local loger_level = {DEBUG = 1, TRACE = 2, INFO = 3, WARN = 4, ERROR = 5, debug = 1, trace = 2, info = 3, warn = 4, error = 5} function new(level, fd, out) local buf = nil --[[ if fd and (fd > 0) then buf = fd_buf.new(fd, fd_buf.FD_BUFFER_WRITE) if not buf then return nil, ‘fd_buffer new fail‘ end end ]] local self = {buf = buf, level = level, out = out} local obj = {} function obj.set_out(out) self.out = out end function obj.set_level(level) self.level = level end function obj.get_level() return self.level end function obj.log(level, str) local d_info = debug.getinfo(3, ‘nl‘) -- local d_info = debug.getinfo(3) d_info.name = d_info.name or ‘main‘ local d_str = string.format(‘[%s()-%s: %s] %s\n‘, d_info.name, d_info.currentline, level, str) if self.out > 0 then --show_debug_info(d_info) io.write(d_str) end if self.buf then self.buf:write(d_str) end end function obj.debug(fmt, ...) if loger_level[self.level] <= loger_level[‘DEBUG‘] then return obj.log(‘DEBUG‘, string.format(fmt, ...)) end end function obj.trace(fmt, ...) if loger_level[self.level] <= loger_level[‘TRACE‘] then return obj.log(‘TRACE‘, string.format(fmt, ...)) end end function obj.info(fmt, ...) if loger_level[self.level] <= loger_level[‘INFO‘] then return obj.log(‘INFO‘, string.format(fmt, ...)) end end function obj.warn(fmt, ...) if loger_level[self.level] <= loger_level[‘WARN‘] then return obj.log(‘WARN‘, string.format(fmt, ...)) end end function obj.error(fmt, ...) if loger_level[self.level] <= loger_level[‘ERROR‘] then return obj.log(‘ERROR‘, string.format(fmt, ...)) end end return obj end return _M
loger模块的简单使用:
local loger = require(‘loger‘) if not loger then print(‘require loger module fail‘) os.exit(-1) end local log = loger.new(‘DEBUG‘, nil, 1) if log then print(‘log.new success‘) --print(log.getlevel()) else print(‘log.new fail‘) end local function test1() log.debug(‘this is debug info‘) log.info(‘this is info level‘) log.warn(‘this is warning level‘) log.info(‘hello %s‘, ‘lua‘) log.warn(‘age %d‘, 28) log.error(‘only one string‘) end log.debug(‘in global test‘) print(‘>>>>>>>>>>>>>>>>>>>>>>‘) test1() print(‘done\n‘)