Lua学习笔记


这是我在学习Lua时记录的一些信息,包含我学习时的代码和记录的函数功能表格。

Lua安装

环境:Centos7.5

yum update -y
yum install lua -y

Lua笔记

脚本编程

通过yum安装的lua默认路径在/usr/bin/lua
创建及运行命令:

mkdir learn_lua
cd learn_lua
vim hello.lua
chmod +x hello.lua
./hello.lua

hello.lua

#/usr/bin/lua

print("hello")

基本语法

注释

-- 单行注释
--[[
    多行注释
--]]

标志符

与其他语言一样。
首字符A-Z|a-z|_开头。
_A-Z开头一般不用,因为一般是Lua保留字。

关键字

and break do if else elseif end false for function in local nil not or repet return then true until while

全局变量

默认情况下,所有变量都是全局的。
变量可以直接赋值,不需要事先声明。访问未赋值的变量显示值为nil。

print(a)
a=1
print(a)

输出如下

nil
1

数据类型

nil

nil表示空。
nil比较时要加上引号。

print(b)
print(type(b)=='nil')

输出

nil
true

把一个变量赋值为nil意味着删除了该变量。

a=2
print(a)
a=nil
print(a)

输出

2
nil

boolean布尔

在Lua中false和nil为假,其他都为真。

number数字

Lua中只有一种数字类型double双精度类型。
数字有以下写法:

print(1)
print(0.1)
print(2e+2)

输出

1
0.1
200

string字符串

字符串由单引号或双引号包裹,也可以由[[]]包裹。

a='a'
b="b"
c=[[测试文字]]
print(a)
print(b)
print(c)

输出

a
b
测试文字

字符串连接使用..。

print(a..b)

输出

ab

当一个字符串中只有数字时,可以与数字作数学运算。
当两个数字使用字符串连接符..拼接时,中间要有空格才能成功拼接,例如2..2拼接不成功,2 .. 2拼接成功。

print("2"+2)
print("2"+"2")
print(2 .. 2)

输出

4
4
22

'#'用来计算字符串长度。

print(#"1234")

输出

4

table表

table是一种类似json的结构,可以添加单独的元素,也可以添加键值对,使用pairs(table)来遍历键值对表。

tb = {
    name="水果",
    child1="苹果",
    child2="菠萝
}
print(tb.name)
for k,v in pairs(tb) do
    print("key="..k.."value="..v)
end

输出

水果
key=child2value=菠萝
key=namevalue=水果
key=child1value=苹果

当成一维数组使用时,Key默认为数字递增,起始值为1,使用ipairs(table)来遍历数组。
表和数组的区别在于使用ipairs和pairs函数分别遍历,pairs能够完全显示数组和表的所有元素,但是ipairs不能显示key不为字符和数字的元素。

tb={"a","b","c"}
for k,v in pairs(tb) do
         print("key="..k.."value="..v)
end

输出

key=1value=a
key=2value=b
key=3value=c

function函数

和其他语言中的函数一样。函数也可以存在变量里。

a=function(e)
    return e
end
print(a(1))

输出

1

由于支持函数存在变量里,所以支持匿名函数调用。

a = function(e)
    print(e)
end
function b(x,func)
    func(x)
end
b(1,a)

输出

1

变量

Lua的变量有三种类型,全局变量、局部变量、表中的域。
Lua中的变量默认都是全局变量,除非用local显式的将一个变量定义为局部变量。局部变量的作用域从声明位置到语句块结束。

a=1
local b=2
print(a,b)
do
    a=2
    b=3
    local d=5
    print(a,b,d)
end
print(a,b,d)

输出

1 2
2 3 5
2 3 nil

赋值语句

Lua可以对多个变量同时赋值。当变量个数大于值的个数时,不足的值会以nil值补齐;当变量个数小于值的个数时,多余的值会被抛弃。如果要对多个变量赋值,需要依次列出多个变量的值。

a=1
b=2
a,b=b,a
print(a,b)
a,b=1,2
print(a,b)
a=1,2
print(a)
a,b,c=1,2
print(a,b,c)

输出

2    1
1    2
1
1    2    nil

多值赋值常用来交换变量的值,或者将函数调用返回给变量。

function num()
    return 9,10
end
a,b=num()
print(a,b)

输出

9 10

索引

table内的元素访问可以使用数组形式,也可以使用.来访问。

tb={
    miantiao="面条",
    tudou="土豆"
}
print(tb.miantiao,tb["tudou"])

输出

面条 土豆

循环

for循环

泛型for循环
tb={
    miantiao="面条",
    tudou="土豆"
}
for k,v in pairs(tb) do
    print(k,v)
end

输出

tudou 土豆
miantiao 面条
数值型for循环

数值型for循环有三个参数,举例for start,end,step do,依次是开始,结束,步长,步长可以省略,省略后步长默认为1。

for i=1,10,2 do
    print(i)
end

输出

1
3
5
7
9

while循环

a=10
while(a>1)
do
    print(a)
    a=a-1
end

输出

10
9
8
7
6
5
4
3
2

注意lua不支持a--这样的写法,只能写作a=a-1。

repeat until循环

a=10
repeat
    print(a)
    a=a-1
until(a<2)

输出

10
9
8
7
6
5
4
3
2

lua支持循环嵌套。

流程控制

function zero(a)
    if(a>0)
    then
        print(a,">0")
    elseif(a<0)
    then
        print(a,"<0")
    else
        print(a,"=0")
    end
end

zero(1)
zero(-1)
zero(0)

输出

1    >0
-1    <0
0    =0

函数

lua支持匿名函数,支持多返回值。

print("---")
--匿名函数
f = function(e)
        print(e)
end
--匿名函数调用
function p(num,fun)
        fun(num)
end
p(1,f)
--多返回值
function mutireturn()
        return 1,2,3
end
print(mutireturn())

输出

---
1
1    2    3

lua支持可变参数。
select("#",...)返回传入可变参数的数量。
select(n,...)返回从第n个开始到最后的可变参数的数组。

function mutiexp(...)
    for i,v in ipairs {...} do
        print(i,v)
    end
    print(select("#",...))
    print(select(2,...))
end
mutiexp(1,"b",3,4,5,"text")

输出

1    1
2    b
3    3
4    4
5    5
6    text
6
b    3    4    5    text

运算符

运算符列表(按照优先级排序)

运算符说明
^乘幂,例如:2^2
not逻辑运算符,非,例如:not(true and false)
-取负,例如:-1
*乘号
/除号
+加号
-减号
..字符串连接符,例如: "1".."2"
<小于号
>大于号
<=小于等于号
>=大于等于号
~=不等于号
==等于号
and逻辑运算符,和,例如:true and false
or逻辑运算符,或,例如:true or false
#求字符串字符总数,返回number,例如:#"123"

字符串

字符串函数

记录一些字符串函数,以备查用。

函数功能示例返回值
string.upper()字符串转为大写string.upper("aBcde")string 返回大写后的字符串
string.lower()字符串转为小写string.lower("AbCDE")string 返回小写后的字符串
string.gsub()字符串替换替换一次CD:string.gsub("ABCDCDS","CD","NN",1),替换全部CD:string.gsub("ABCDCDS","CD","NN")string number 返回值为替换后的字符串、替换次数
string.find()字符串查找string.find("ABCDEF","BC")number number 返回子串在字符串中第一次出现的起始位置和结束位置。位置说明:例:A字符的位置为1。
string.reverse()字符串反转string.reverse("Lua")string 返回反转后的字符串
string.format()字符串格式化string.format("number is %d",2)string 返回格式化后的字符串
string.char()ASCII十进制数字转换为字符串string.char(65,66,67)string 返回ASCII十进制数字转换为字符后连接在一起的字符串
string.byte()字符串首字母/指定字母转换为十进制ASCIIstring.byte("ABCD") string.byte("ABCD",4)number 返回指定字母的ASCII码
string.len()字符串长度string.len("ABC")number 返回字符串长度
string.rep()字符串重复string.rep("ABC",2)string 返回重复的字符串
string.gmatch()字符串迭代器函数for word in string.gmatch("ABCD E F","%a+") do print(word) endstring 在原字符串中查找每次迭代返回一个与模式匹配的字符串
string.match()字符串匹配函数string.match("A BC D","%a+")多个string 返回匹配的字符串
匹配模式

记录一些字符串匹配模式,以备查用。

字符模式
.(点)与任何字符配对
%a与任何字母配对
%c与任何控制符配对(例如n)
%d与任何数字配对
%l与任何小写字母配对
%p与任何标点(punctuation)配对
%s与空白字符配对
%u与任何大写字母配对
%w与任何字母/数字配对
%x与任何十六进制数配对
%z与任何代表0的字符配对
%x(此处x是非字母非数字字符): 与字符x配对. 主要用来处理表达式中有功能的字符(^$()%.[]*+-?)的配对问题, 例如%%与%配对
[数个字符类]与任何[]中包含的字符类配对. 例如[%w_]与任何字母/数字, 或下划线符号(_)配对
1与任何不包含在[]中的字符类配对. 例如2与任何非空白字符配对
  • 单个字符类匹配该类别中任意单个字符;
  • 单个字符类跟一个 '*', 将匹配零或多个该类的字符。 这个条目总是匹配尽可能长的串;
  • 单个字符类跟一个 '+', 将匹配一或更多个该类的字符。 这个条目总是匹配尽可能长的串;
  • 单个字符类跟一个 '-', 将匹配零或更多个该类的字符。 和 '*' 不同, 这个条目总是匹配尽可能短的串;
  • 单个字符类跟一个 '?', 将匹配零或一个该类的字符。 只要有可能,它会匹配一个;
  • %n,这里的 n 可以从 1 到 9; 这个条目匹配一个等于 n 号捕获物(后面有描述)的子串。
  • %bxy,这里的 x 和 y 是两个明确的字符; 这个条目匹配以 x 开始 y 结束, 且其中 x 和 y 保持 平衡 的字符串。 意思是,如果从左到右读这个字符串,对每次读到一个 x 就 +1 ,读到一个 y 就 -1, 最终结束处的那个 y 是第一个记数到 0 的 y。 举个例子,条目 %b() 可以匹配到括号平衡的表达式。
  • %f[set],指边境模式; 这个条目会匹配到一个位于 set 内某个字符之前的一个空串, 且这个位置的前一个字符不属于 set 。 集合 set 的含义如前面所述。 匹配出的那个空串之开始和结束点的计算就看成该处有个字符 '0' 一样。

数组

支持多维数组。数组的第一个元素的下标是1。

a={"a","b","c","d"}
print(a[1])
b={}
b[1]={}
b[2]={}
b[1][1]=0
b[1][2]=1
b[2][1]=3
b[2][2]=4
print(b[2][1])

输出

a
3

迭代器

迭代器可以遍历集合中的每个元素。

无状态的迭代器

迭代器有两个参数,状态常量和控制变量,需要返回两个参数,一个控制变量,一个处理后的值。

function sq(con,var)
    if(var<con)
    then
        var=var+1
        return var,var*var
    end
end

for var,varvar in sq,3,0 do
    print(var,varvar)
end

输出

1    1
2    4
3    9

多状态的迭代器

多状态迭代器使用table保存状态常量,控制变量也可以放在table里,因此,多状态迭代器只需要一个变量传入。

a={"a","b","c"}
function d(collection)
    local index=0
    local len=#collection
    return function()
            index=index+1
            if index<=len
            then
                return collection[index]
            end
    end
end

for e in d(a) do
    print(e)
end

输出

a
b
c

table表

table表函数

记录一些table表函数,以备后用。

函数功能示例返回值
table.concat()把table里的元素连接成字符串table.concat({"a","b"},",",1,2)string 返回连接后的字符串
table.insert()在指定位置插入一个元素,可不指定位置,默认插入在末尾table.insert({},2,"a")table 返回插入后的table
table.remove()删除指定位置的一个元素,可不指定位置,默认删除最后一个元素table.remove({"a"},1)table 返回删除后的table
table.sort()排序,按照字母表和数字顺序对table排序,可指定升序降序table.sort({})table 返回排序后的table

模块与包

模块的创建与使用

创建模块就是新建一个table,把字段和函数存进table,再返回这个table即可。
moudle.lua

moudle={}
moudle.con="定义一个常量"

function moudle.fun()
    return "定义一个函数"
end

local function private_fun()
    print("这是一个私有函数")
end

function moudle.use_private_fun()
    private_fun()
    print("私有函数只能由全局函数调用,外部不可直接使用")
end

return moudle

加载模块使用require()函数。
use_moudle.lua

require("moudle")
print(moudle.fun())
print(moudle.con)

也可以给加载的模块一个别名,便于使用。
use_moudle_cname.lua

m=require("moudle")
m.use_private_fun()

加载机制

Lua会尝试从以下路径加载文件,不在这些路径中的文件无法加载。

  • package.path中的文件
    在centos中,package.path路径为:
./?.lua;/usr/share/lua/5.1/?.lua;/usr/share/lua/5.1/?/init.lua;/usr/lib64/lua/5.1/?.lua;/usr/lib64/lua/5.1/?/init.lua
  • 自定义的LUA_PATH
export LUA_PATH="~/lua/?.lua;"
  • 当前文件夹
    推荐在当前文件夹下写完所有lua模块,便于加载。

Lua中还可以加载c包。

metatable元表

元表是对table的一种扩展,元表本身也是一个table。给一个table设置元表使用setmetatable(),获取一个table的元表使用getmetatable()。
setmetatable()返回的是被设置元表的table。

tb={}
metatb={}
setmetatable(table,metatb)
metatb_tmp=getmetatable(table)

__index键

当一个table中没有一个键时,Lua会寻找该table的元表的__index键,并在其中试图找到该键。
使用__index键可以指定一个新的table扩展原table的键值对。

tb={}
other={con="ab"}
metatb=setmetatable(tb,{__index=other})
print(tb.con)
print(other.con)
print(metatb.con)

输出

ab
ab
ab

如果__index中存的是一个函数,那么操作的table和table请求的键名要当做参数传给这个函数。

tb={}
metatb=setmetatable(tb,{
    __index=function(tb,key)
        return key
    end
})
print(tb.a)
print(metatb.a)

输出

a
a

__newindex

__index在查找table值的时候使用。
__newindex则在新建table值的时候调用,相当于拦截了所有对table的新添加键值对传给元表。

tb={key1="a"}
metatb={}
tb=setmetatable(tb,{__newindex = metatb})
tb.key2="b"
print(tb.key2,metatb.key2)
tb.key1="c"
print(tb.key1,metatb.key1)

输出

nil    b
c    nil

coroutine协同程序

coroutine与线程类似,拥有独立的堆、局部变量、指针指令,同时又与其他coroutine共享全局变量和其他大部分东西。
coroutine与线程的区别是,拥有多个线程的程序可以在同时运行几个线程,但是coroutine需要互相协调运行。
在任一指定时刻只能有一个coroutine运行,并且这个coroutine只有在明确被要求挂起时才会挂起。
在等待同一个线程锁的多个线程类似coroutine。

函数功能
coroutine.create()创建coroutine,参数是一个函数。
coroutine.resume()重启/继续corourine,第一个参数是coroutine实例,第二个参数为coroutine初始化时定义的函数的参数。
coroutine.yield()挂起coroutine。
coroutine.status()返回coroutine的状态,有三个状态:dead,suspend,running
coroutine.running()返回正在运行的coroutine线程的线程号

使用示例:

co=coroutine.create(
    function(e)
        print(e)
        print(coroutine.running(co))
    end
)
coroutine.resume(co,2)
print(coroutine.status(co))

输出

2
thread: 0xa8c520
dead

面向对象

Student={
        name="default",
        age=18
}
function Student:new(obj,name)
        obj=obj or {}
        setmetatable(obj,self)
        self.__index = self
        name = name or "default name"
        self.name = name
        return obj
end

function Student:printName()
        print(self.name)
end

stu1 = Student:new(nil,"小明")
stu1:printName()

输出

小明

垃圾回收

Lua采用了自动垃圾回收。
Lua使用了一个垃圾收集器来收集所有不会被用到的对象。
垃圾收集器默认以内存分配的2倍速工作,这个速度是可调的。

函数功能
collectgarbage("collect")使用函数手动开启一次完整的垃圾收集。
collectgarbage("restart")重启垃圾收集器

以上即是我学习Lua的笔记,我的邮箱是wubo@wubo.net.cn,欢迎和我讨论。


  1. 数个字符类
  2. %s

声明:物博网|版权所有,违者必究|如未注明,均为原创|本网站采用BY-NC-SA协议进行授权

转载:转载请注明原文链接 - Lua学习笔记


喜欢安全与WEB开发