淘先锋技术网

首页 1 2 3 4 5 6 7

在FreeSWITCH中,Lua模块是默认加载的。在所有嵌入式脚本语言中,它是最值得推荐的语言。首先它非常轻
量级,mod_lua.so经过减肥(Strip)后只有272KB;另外,它的语法相对的简单。有人做过对比,在嵌入式的脚
本语言里,如果Python得2分,Perl得4分,JavaScript得5,则Lua语言可得10分 [2],由此可见一斑。
另外,Lua模块的文档也是最全的。笔者在使用其他语言(如JavaScript)甚至写Event Socket程序时也经常
参考Lua模块的文档。
注意
FreeSWITCH完全内置了Lua解释器,因此与操作系统上的Lua版本以及各种第三方库一点关系都没有,详细的
配置信息可以参考conf/autoload_configs/lua.conf.xml。
另外,自2013年11月中旬起,FreeSWITCH中的Lua解释器升级到了Lua 5.2版本,因此,读者在写Lua脚本时要
注意使用与Lua 5.2兼容的语法。而原来的Lua模块(基于Lua 5.1)则被移动到了源代码目录下的src/mod/legacy目录
中,如果需要Lua 5.1的用户可以自行编译该版本。
16.2.1 Lua语法简介
Lua的语法非常简洁易懂,有人说:如果你会其他编程语言,则在30分钟内就能学会它 [3]。
大家都知道,如果有某种语言的编程经验,则学一种新的语言时可以对比着学。在这里,我们对比大家比较
熟悉的JavaScript语言 [4]来学习Lua。
1.相似性
Lua与JS(JavaScript的缩写,下同)有很多相似的地方,简述如下。
·变量无需声明。Lua与JS都是“弱”类型的语言(不像C),所以它们不需要事先声明变量的类型。
·区分大小写。Lua和JS都是区分大小写的。true和false分别代表布尔类型的真和假,true与True或TRUE是完
全不同的。
·函数可以接受个数不定的参数。与JS类似,在Lua中,与已经声明的函数参数个数相比,实际传递的参数个
数可多可少,如:
function showem( a, b, c )
print( a, b, c )
end
showem( 'first' ) --> first nil nil
showem( 'first', 'second' ) --> first second nil
showem( 'first', 'second', 'third' ) --> first second third
showem( 'first', 'second', 'third', 'fourth' ) --> first second third
在Lua中,个数不定的参数列表使用“...”(称为vararg expressions)来表示,如:
function showem(a, b, ...)
local output = tostring(a) .. "\t" .. tostring(b)
local theArgs = { ... }
for i,v in ipairs(theArgs) do
output = output .. "\t#" .. i .. ":" .. v
end
print(output)
end
showem('first' ) --> first nil
showem('first', 'second') --> first second
showem('first', 'second', 'third') --> first second #1:third
showem('first', 'second', 'third', 'fourth') --> first second #1:third #2:fourth
·哈希可以用方括号或点方式引用。哈希表是编程语言中一种重要的数据结构。在Lua中,哈希表用Table来
实现,在JS中,用稀疏在数组实现。无论如何,在两者中都可以使用如下的语法引用,如:
theage = gavin['age']
theage = gavin.age
·数字区别不大。在JS和Lua中,整数和浮点数是没有区别是的。它们在内部都是以浮点数表示。在Lua中,
所有的数字类型都是number类型。
·分号是可选的。两者类似,在不产生歧义的情况下,行尾的分号可以有,也可以没有。不同的是对待分号
的方式,在JS中,按惯例是包含分号的,而在Lua中,惯例是不包含分号的。
·默认全局变量。在JS中,如果用var声明一个变量并赋值,则它是本地变量;如果不用var声明,默认就是全
局的,如:
function foo( )
{
var jim = "This variable is local to the foo function";
jam = "This variable is in global scope";
}
而在Lua中也类似,用local声明一个本地变量,省略local时则默认为全局变量:
function foo( )
local jim = "This variable is local to the foo function";
jam = "This variable is in global scope";
end
·使用双引号和单引号表示字符串。在JS和Lua中,字符串是用引号引起来的,并且单引号和双引号的作用没
有任何不同 [5]。引号要配对使用,但这两种引号可以混合以避免使用转义符,必要时可以使用“\”来转义,如
(其中,箭头后面为实际变量的值):
local book = "Seven's Book"; --> Seven's Book
local book = 'Seven\'s Book'; --> Seven's Book
local book = '"Awsome" book of Seven'; --> "Awsome" book of Seven
local book = "\"Awsome\" book of Seven"; --> "Awsome" book of Seven
·函数是一等公民。在JS和Lua中,函数是一等公民,这意味着,你可以将它赋值给一个变量,将它作为参数
传递,或者直接加上括号进行调用,如在Lua中:
1 mytable = { }
2 mytable.squareit = function( x )
3 return x * x
4 end
5 thefunc = mytable.squareit
6 print( thefunc( 7 ) ) --> 49
其中,第1行声明一个Table类型的变量mytable;第2~4行定义一个匿名函数,并将它赋值给mytable的
squareit成员变量;第5行将上述成员变量的值又赋值给了一个变量thefunc。至此,thefunc实际上就代表第2行
至第4行定义的匿名函数。最后,在第6行就可以通过thefunc引用该函数,该函数对输入的参数7进行平方计算
(x*x),最后得到结果49。
·函数都是闭包。在JS和Lua中,函数都是闭包。简单来说,这意味着函数可以随时访问该函数在定义时可以
访问的本地变量,尽管在以后调用时这些本地变量逻辑上已经“失效”了。比如下面的Lua例子中,inBaseValue中
在定义时有效,却能在调用时照样使用它。
function MakeAdder( inBaseValue )
return function( inValueToAdd )
return inBaseValue + inValueToAdd
end
end
add10 = MakeAdder( 10 )
add30 = MakeAdder( 30 )
print( add10( 1 ) ) --> 11
print( add10( 6 ) ) --> 16
print( add30( 3 ) ) --> 33
2.区别
Lua与JS又有很多区别,简述如下:
·单行和多行注释不同。JS使用“//”做单行注释,而Lua使用“--”。JS使用“”来做多行注释,而
Lua中使用“--[[...]]”(注意,这里的“...”表示实际被注释的内容)。
JS中多行注释不能嵌套,解析器将在遇到第一个“*/”时终止该注释,而在Lua中,则可以使用类似“--[===
[...]===]”的方式,通过在方括号中多加几个等号(前后等号的数量要匹配)来改变最外层的注释。参考以下
Lua注释:
--
local jim = "This is not commented"
--[[
local foo = "
" "
local bar = "
" "
--]]
local jam = "
" "
---[[
local foo = "
" "
local bar = "
“- “-

--]]
--[==[
--[[
local foo = "foo"
local bar = "bar"
--]]
--]==]
·用end终止程序块。Lua与Ruby类似,使用end来代替JS中的大括号来终止程序块,如下面是Lua中终止程序
块的语法:
function foo( )
--my code here
end
if foo( ) then
--my code here
end
for i=0,1000 do
--my code here
end
·使用nil代表空值。类似Ruby,在Lua中,使用nil代表空值,在JS及C语言中则使用null或NULL。
在JS中,空字符串("")和0在条件测试中都为假(false)。而在Lua中,nil和false是仅有的
非“真”(True)值,其他所有的都表示测试结果为真。

Lua中任何值都可以作为Table的键(Key)。在JS中,对象(Object)的所有键都是字符串(如myObj[11]与
myObj["11"]是相同的),而在Lua中,字符串、数字、甚至另一个Table都可以是键。参见如下Lua代码:
a = {}
b = {}
mytable = {}
mytable[1] = "The number one"
mytable["1"] = "The string one"
mytable[a] = "The empty table 'a'"
mytable[b] = "The empty table 'b'"
print( mytable["1"] ) --> The string one
print( mytable[1] ) --> The number one
print( mytable[b] ) --> The empty table 'b'
print( mytable[a] ) --> The empty table 'a'
·Lua中没有数组,任何复杂的数据类型都是Table。在JS里有明确的数组对象,并且有对应的操作数组的方
法,如:
var myArray = new Array( 10 ); //
10 10
var myArray1 = [ 1, 2, 3 ]; //
3 3
myArray1.pop(); //
而在Lua中,对象是Table、prototype是Table、哈希是Table、数组是Table、Table是Table、什么都是
Table。
Lua中的所谓数组本身是一个Table,它相当于JS里的稀疏数组,只是它的第一个元素的下标是从1开始的,而
不是0。可以使用Table的语法来创建数组。如下面Lua代码中的两种方法是等价的:
people = { "Alice", "Bob", "Carl" }
people = { [1]="Alice", [2]="Bob", [3]="Carl" }
如果拿Table当数组来用,可以使用两种方法来获取和设置数组的大小,并允许数组中有空值存在,如:
people = { "Alice", "Bob", "Carl" }
print( table.getn( people ) ) --> 3
people[ 7 ] = "Someone Else "
print( table.getn( people ) ) --> 3
print( people[ 10 ] ) --> "Some Dude"
for i=1,table.getn( people ) do
print( people[ i ] )
end
--> Alice
--> Bob
--> Carl
table.setn( people, 7 )
print( table.getn( people ) ) --> 7
for i=1,table.getn( people ) do
print( people[ i ] )
end
--> Gavin
--> Stephen
--> Harold
--> nil
--> nil
--> nil
--> Someone Else
·数字、字符串以及Table都不是对象。与面向对象概念里面的对象不同,数字、字符串以及Table本质上都
不是对象。
Lua仍然是面向过程的编程,大多数操作可以通过库函数实现,如:
print(string.len(mystring) ) --> 11
print(string.lower(mystring)) --> hello world
其中,string.len是一个函数,实际上string本身是一个Table。从Lua5.1起,也支持一些类似面向对象的语
法,如上面的例子等价于:
mystring = "Hello World"
print(mystring:len()) --> 11
print(mystring:lower()) --> hello world
在上面的例子中,通过使用“:”,把mystring看成一个对象,然后len和lower就类似于这个对象的方法。便
实际上,Lua是在内部把mystring这个假的“对象”特殊处理了,找到它所对应的数据类型(string)后,调用实
际的string.len(),并把mystring作为该函数的第一个参数,所以mystring:len()与string.len(mystring)是等
价的。
·没有++和+=。在Lua中没有++和+=这样的缩写形式,所以变量自加必须用以下方式:
local i = 0;
i = i + 1;
字符串的拼接是使用“..”操作符实现的,如:
local themessage = "Hello"
themessage = themessage .. " World"
如果把一个字符串和一个数字相加,Lua会试图将字符串转换成数字,如:
print(10 + "2") --> 12
print(10 + "a") -->
attemapttt etmop tp etrof opremr faorrimt hamreittihcm eotni ca osnt rai nsgt rvianlgu evalue
·没有三目运算符。JS或C中的“a?b:c”语法是很贴心的,但在Lua中没有。不过,Lua中有个“短路”语法,
与该功能类似,如:
local foo = (math.random( ) > 0.5) and "It's big!" or "It's small!"
local numusers = 1
print( numusers .. " user" ..
(numusers == 1 and " is" or "s are") .. " online.")
--> 1 user is online.
numusers = 2
print( numusers .. " user" ..
(numusers == 1 and " is" or "s are") .. " online.")
--> 2 users are online.
·模式匹配。正则表达式是很方便的字符串匹配工具。与JS以及其他语言不同,为了保持Lua的小巧且减少对
其他库的依赖,Lua没有使用常用的POSIX(regexp),也没有使用PCRE(Perl兼容的正则表达式),而是自己实现
了模式匹配算法,其语法也有很大不同。
模式(Pattern)实际上就是Lua中的正则表达式。它与普通正则表达式最大的不同就是使用“%”而不是使
用“\”来转义。Lua模式中的字符分类如表16-1所示。
表16-1 Lua中的模式

除此之外,它还有一些具有魔法含义的特殊字符,这些字符有:
( ) . % + - * ? [ ] ^ $
它们的含义都与PCRE里的差不多的,其中“-”的含义与“*”类似,都是重复前一个字符0次或多次,不同的
是,“*”为最大匹配,它会尽量匹配更长的字符串,而“-”为最小匹配,它会尽量匹配更短的字符串。