Lua语法
数据类型
Lua是一个动态类型语言,一个变量可以存储任何类型的值。编写redis脚本会用到的类型
类型名 | 取值 |
空(nil) | 空类型只包含一个值,即nil。nil表示空,所有没有赋值的变量或表的字段都是nil |
布尔(boolean) | 布尔类型包含true和false |
数字(number) | 整数和浮点数都是使用数字类型存储,如1、0.23、3.5e20等 |
字符串(string) | 字符串类型可以存储字符串,且与redis的键值一样都是二进制安全的。字符串可以使用单引号或双引号表示,两个符号是相同的,比如'a'和"a",字符串中可以包含转义字符,如\n,\r等 |
表(table) | 表类型是Lua语言中唯一的数据结构,既可以当数组有可以当字典,十分灵活 |
函数(function) | 函数在Lua中是一等值(first-class-value),可以存储在变量中、作为函数的参数或返回结果 |
变量
Lua的变量分为全局变量和局部变量。全局变量无需声明就可以直接使用,默认为nil
a=1 --为全局变量赋值
print(b) --无需声明即可使用,默认是nil
a = nil --删除全局变量a的方法是将其赋值为nil。全局变量没有声明和未声明之分,只有非nil和nil区别
在redis脚本中不能使用全局变量,只允许使用局部变量以防止脚本之间的相互影响,声明局部变量的方法为local变量名
local c --声明一个局部变量c,默认值是nil
local d =1 --声明局部变量并赋值1
local e,f --同时声明多个局部变量
变量名必须是非数字开头,只能包含字母、数字和下划线,区分大小写。变量名不能和Lua的保留关键字相同,保留关键字如下:
and break do else elseif
end false for function if
in local nil not or
repeat return then true until while
局部变量的作用域为从声明开始到所在层的语句块末尾,比如
local x =10
if true then
local x = x+1
print(x)
do
local x = x+1
print(x)
end
print(x)
end
print(x)
依次输出:
11 12 11 10
注释
单行注释以--开始,到行尾结束,一般习惯在--后面跟上一个空格
多行注释以--[[开始,到]]结束
赋值
Lua支持多重赋值,比如:
local a,b = 1,2
local c,d = 1,2,2 -- c的值是1,d的值是2,3被舍弃了
local e,f = 1 -- e的值是1,f的值是nil
在执行多重赋值是,lua会先计算所有表达式的值,比如
local a = {1,2,3}
local i = 1
i,a[i] = i+1,5 变为 i,a[1] = 2,5 赋值后i为2, a则为{5,2,3}
操作符
Lua有以下5类操作符
1> 数学操作符。 + - * / %(取模) - (取负) 幂运算符 ^
print('1'+1) -- 2 数学操作符的操作数如果是字符串会自动转换为数字
2> 比较操作符 结果一定是boolean
3>逻辑操作符
操作符 | 说明 |
not | 根据操作数的真和假相应地返回false和true |
and | a and b 中如果a为真则返回b,否则返回a |
or | a or b 如果 a 是true 则返回 a,否则返回b |
只要操作数不是nil或false,逻辑操作符就认为操作符是真,否则是假。特别需要注意的是即使是0或者空字符串也被当做是真
print(1 and 5) -- 5
print(1 or 5) -- 1
print(not 0) -- false
print('' or 1) -- ''
Lua的逻辑操作符支持短路,也就是说对于false and foo() ,Lua不会去调用foo(),or 操作符类似
4> 连接操作符。 连接操作符只有一个 : ..,用来连接两个字符串,比如
print('hello'..''..'world') -- hello world
连接操作符会自动把数字类型转为字符串类型
5> 取长度操作符。 # 例如 print(#'hello') -- 5
运算符的优先级(优先级依次降低)
^
not # - (一元)
* / %
+ -
..
< > <= >= ~= ==
and
or
if语句
Lua的if语句格式如下:
if 条件表达式 then
语句块
elseif 条件表达式 then
语句块
else 语句块
end
note:
在Lua中只有nil和false才是假,其余值都是真,包括空字符串和0,都是认为是真的。这是一点容易出错的地方。
比如说:
if redis.call('exists','key') then
exists = true
else
exists = false
end
这个exists返回的就是1或0,一定返回的是真,就有问题了,改为 if redis.call('exists','key') == 1 才正确
Lua与javascript每个语句都可以;结尾,都是省略的,当然也可以写在一行,最好分行写
循环语句
Lua支持 while,repeat 和 for循环语句
while 语句的形式为:
while 条件表达式 do
语句块
end
repeat语句的形式为:
repeat 语句块 until 条件表达式
for语句有两种形式,一种是数字形式:
for 变量 = 初值 ,终值,步长 do 语句块 end
其中步长可以省略,默认步长是1,比如使用for循环计算1~100的和
local sum = 0
for i=1 ,100 do sum = sum+1 end
提示: for语句中的循环变量是局部变量,作用域为for循环体内,虽然没有使用local声明,但不是全局变量
for 语句的通用形式为: for 变量1,变量2,....变量n in 迭代器 do 语句块 end
表类型
表是Lua中唯一的数据结构,可以理解为关联数组,任何类型的值(除了空类型)都可以作为表的索引
表的定义方式:
a = {} -- 将变量a赋值为一个空表
a['field'] = 'value'
print(a.field); --打印内容为'value',a.field是a['field']的语法糖
或者定义:
people = {name = 'zhouy',age = 29 } print {people.name} --打印内容为Bob
当索引为整数的时候表和传统的数组一样,例如:
a = {} a[1] = 'zhouy' a[2] = 'Jeff' 可以写成这样: a = { 'zhouy','jeff'} print{a[1]}
note: Lua 约定数组的索引是从1开始的,而不是0
表的遍历方式:
1. 通用形式的for语句遍历数组
for index,value in ipairs(a) do
print(index)
print(value)
end
ipairs是lua内置的函数,实现类似迭代器的功能
2.使用数字形式的for语句遍历数组
for i =1 ,#a do
print(i)
print(a[i])
end
#a作用是获取表a的长度
3. 迭代器pairs用来遍历非数组的表值。
people = {name = 'zhouy',age = 29}
for index, value in pairs(people) do
print (index)
print(value)
end
pairs和ipairs的区别是前者会遍历所有值不为nil的索引,而后者只会从索引1开始递增遍历到最后一个值不为nil的整数索引
函数
函数的定义为:
function (参数列表)
函数体
end
可以将其赋值为一个局部变量,比如
local square = function(num ) return num*num end
如果没有参数,括号也不能省略。Lua还提供了一个语法糖来简化函数的定义,比如
local function square (num)
return num*num
end
这段代码会转换为:
local square
square = function (num) return num*num
end
如果实参的个数小于形参的个数,则没有品牌到的形参的值为nil.相对应的,如果实参的个数大于形参的个数,则多出来的实参
会被忽略。如果希望捕获多出的实参,可以让最后一个形参为...。比如,希望传入若干个参数计算这些数的平方
local function square (...)
local argn = {...}
for i=1,#argv do
argv[i] = argv [i] * argv[i]
end
unpack函数用来返回表中的元素
标准库
String库
1>获取字符串长度 string.len(string)
2>转换大小写 string.lower string.upper
3>获取子字符串 string.sub(string,start,end) 索引从1开始,-1代表最后一个元素。end参数如果省略,默认是-1
Table库
1> 将数组转为字符串
table.concat(table[,sep[, i[, j ] ] ] );
举个例子
print (table.concat({1,2,2},',',2); ---> '1,2,22'
2>向数组中插入元素
table.insert(table,[post,] value) ;向 指定索引位置pos插入元素value,并将后面的元素顺序后移,默认pos的值是数组长度加1,即在数组尾部插入,注意索引从1开始的
3> 从数组中弹出一个元素
table.remove(table [,pos]) 从指定索引位置删除元素,并将后面的元素前移,返回删除元素的值
其他需要了解的:
cjson.encode :序列化为字符串
cjson.decode :将序列化后的字符串还原为表
cmsgpack.unpack 将序列化后的字符串还原为表