lua学习笔记

公司有个项目涉及到网络通信,用到了websocket协议。其中和底层设备的通信模块用C++来做的,并且用到lua来做C++的扩展。之前用的最多就是PHP和javascript。突然用lua来做东西好多不习惯,不过上手之后觉得也挺好。lua小巧简洁,使用起来很灵活。

Lua是一个被设计成用于扩展C/C++编程的轻量级脚本语言,它的目标是成为一个很容易嵌入其它语言中使用的语言。Lua让C/C++编写的代码调用Lua脚本,同时C/C++函数也能够在Lua脚本中调用。与C/C++代码的交互性,让Lua在应用程序开发中有着广泛的应用基础。很多应用程序使用Lua作为自己的嵌入式脚本语言,以此来实现可配置性、可扩展性。

由于lua定位于一个很容易嵌入其它语言中使用的语言,不适合作为开发独立应用程序的语言。所以它只包括一个精简的核心和最基本的库,有一些最基本的内置函数来应对开发需要。要实现一些较为复杂或是比较具体的功能,则需要我们自己写代码来完成。以下我开发中遇到的一些问题,在此记录以备学习之用。

1.关于日期的

已知某一日期,比如“2014-12-04”,想要取得前一天日期,即”2014-12-03“。当然,举一反三或是取向前固定时间的日期或是向后固定时间的日期。

如果是PHP来做的话,相对要简单。

PHP代码:

$date = "2014-12-04";
$pre_date = date("Y-m-d", strtotime($date) - 60*60*24);
echo $pre_date;

用lua实现的话还是同样的思路,获取当前日期的时间戳,减去一天时间的秒数(60*60*24)。再用相应的日期函数来定义要获得的日期格式。但是lua要相对麻烦一点。lua最常用的关于日期和时间的函数是os.date()和os.time()。

os.date ([format [, timestamp]]),第一个参数format用于定义返回的日期时间格式,第二个参数timestamp为时间戳。两个参数都可以省略,默认返回当前的日期时间,如“12/04/14 21:56:35”。

os.time([table]), os.time()函数的参数类型是table(这是lua中的常用的数据类型,这里不做展开),该函数按table的内容返回一个对应的时间值(数字),若不带参数则返回时间戳。即返回的是参数中定义的时间点到1970 年 1 月 1 日 00:00:00(Unix 纪元)的秒数。如os.time({year=2014, month=12, day=04, hour=0, min=0, sec=0})返回的是2014-12-04 00:00:00到1970-01-01 00:00:00的秒数,值为1417622400。

对了两个函数有一定了解,就可以实现了。先对字符串“2014-12-04”截取分别获得年、月、日的值。然后通过os.time()获取“2014-12-04”的时间戳,再减去一天的秒数。最后再用os.date()格式化得到需要的日期格式。

lua代码:

local date = "2014-12-04"
local year = string.sub(date, 1, 4)
local month = string.sub(date, 6, 7)
local day = string.sub(date, 9, 10)
local pre_date = os.date("%Y-%m-%d", os.time({year = year, month = month, day = day}) - 60*60*24)
print(pre_date)

以上。

要获取向前固定时间的日期或是向后固定时间的日期修改 -60*60*24处即可。

2.关于比较运算

这里主要讨论lua中的相等比较运算“==”。lua中的相等比较(==)是判断两个数据的类型和内容是否都相同,而PHP的相等比较(==)则只对比两个数据的内容是否相同,类型是否相同则不考虑。若要同时判断类型和内容是否相同,用的比较运算符是"==="(三个等号)。

PHP代码:

$string = "34";
$number = 34;

if($string == $number){
    echo "match";
}else{
    echo "no match";
}
//输出match

echo "<br>";

if($string === $number){
    echo "match";
}else{
    echo "no match";
}
//输出no match

lua代码:

local str = "34"
local num = 34
if str == num then 
     print("match")
else 
     print("no match")
end

--输出 no match

可见PHP和lua中关于比较运算的不同,要特别注意,不要想当然。

lua中的os.date()函数返回的就是字符串类型的值。之前我用os.date(“%H”)获取当前时间的小时和数字匹配比较,如 if os.date("%H") == 9 then 就会始终匹配不上。应为 if os.date("%H") == "9" then才有可能匹配上。特此说明,愿为他人之鉴。

3.关于table(关系表)拆分

lua中的table是一种特殊的数据类型,叫做关系表类型,我们可以把这个类型看作是一个数组。在lua中可以用除了nil以为的任意类型来作为关系表索引和和关系表内容。

在lua中定义表的方法很简单

local tab = {}
tab[1] = 11
tab["second"] = 12
tab.three = 13
print(tab[1], tab.second, tab.three)
    
--输出 11  12  13

以上代码首先定义了一个空表,当然可以在定义时让表就有内容,如 local tab = { 2, "test"}。然后给空表添加了三个元素。索引值是字符串时,可以用tab.second这种方式获取到。如果不写索引,则索引就会被认为是数字,索引值自1开始加1递增。如local tab = { 2, "test"},可以通过tab[1]和tab[2]获取到2和"test"。

关于lua的table用法简单介绍这些。

我在开发时用到udp协议发送数据,但发送数据有大小限制。最终确定要将发送内容中的一部分字符串分包发送,而这部分字符串时通过一个关系表得到。所以要将这个表拆分为多个表,然后在多次转换获取字符串分别发送。这个表的索引都是数字,从1开始编号的。

如果用PHP做这个东西的话,则相对简单。

PHP代码:

$arr = array();
for($i = 0; $i < 300; $i ++){
    $arr[] = $i;
}

$new_arr = array_chunk($arr, 50);

echo '<pre>';
print_r($new_arr);
echo '<pre>';

PHP已内置了array_chunk()函数,足以满足以上所说的需求,并且不要求数组索引值必须为数字。关于array_chunk(array,size,preserve_key)的详细用法,读者可以到PHP手册中详细了解,在此不再赘述。

那么lua如何实现呢,先看代码,lua代码:

local tab = {}
local newTab = {}
local offset = 70

for i=1, 300 do
    tab[i] = i
end

local count = math.ceil(#tab/offset)
for i=1, count do
    newTab[i] = {}
end
                
for k, v in pairs(tab) do                
    table.insert(newTab[math.ceil(k/offset)], v)    
end

--[[
newTab = { [1] = {1, 2, 3, ..., 70}
           [2] = {71, 72, 73, ..., 140}
           [3] = {141, 142, 143, ..., 210}
           [4] = {211, 212, 213, ..., 280}
           [5] = {281, 282, 283, ..., 300}
         }
]]--

tab是已知的关系表,newTab是要得到的关系表,offset是tab拆分后小关系表的长度,即所包含元素个数。首先初始化tab为一个包含300个元素的关系表,索引值从1到300。现在要得到newTab为代码最后注释部分内容。

然后,local count = math.ceil(#tab/offset)。#tab获取关系表tab中元素个数,另一种方法为table.getn(tab)。注意这两种方法只能正确获取关系表中索引从1开始的,连续递增的元素的个数。使用时要慎重。math.ceil()是lua中的向上取整,相关的math.floor()是向下取整。ceil是天花板,而floor是地板的意思。很形象,PHP中也有这两个函数。math.ceil(#tab/offset)是的道newTab中的元素个数。初始化好newTab。

最后遍历tab表,按照条件将数据插入到新表newTab中。newTab[math.ceil(k/offset)]的类型是表,之前已经定义。math.ceil(k/offset)是索引值,在这里值可能为1~5。table.insert(newTab[math.ceil(k/offset)], v)函数将v值插入到表newTab[math.ceil(k/offset)]中。这样newTab的就是要获取的表内容了。代码最后注释部分即为所得到的表结构。

以上就是我在用lua开发时候遇到的一些小问题,和PHP做了相关比较。PHP在一些具体的功能应用上都做了封装,使用起来比较简单,不用自己去定义实现。而lua则更基础灵活,运行速度会更快。各有利弊吧。

初次使用lua做东西,算是初窥门径。以上有表述不准确和不正确的地方,请大家斧正。

参考资料:http://developer.51cto.com/art/201108/281135.htm

http://www.cnblogs.com/ly4cn/archive/2006/08/04/467550.html

http://www.cnblogs.com/whiteyun/archive/2009/08/10/1542913.html

http://blog.csdn.net/jphaoren/article/details/5807578