之前因为工作的需要学习了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')