跳转至

lua脚本语言

lua脚本语言

更新日期: 2020-06-17


1. lua初探

1.1 lua的特点

可以归结为如下几个特点

1
2
3
4
5
跨平台和语言      -- 在linux,windows,Android,IOS上都可以使用,支持所有主流语言。可以说学了不会吃亏,不会上当。
                -- 号称是最快的脚本语言,经常用于制作游戏脚本。
嵌入式         -- 通常不单独使用,而是嵌入到宿主语言中使用。能嵌入所有主流语言,甚至是其他脚本语言,适应性很广。
语法简洁        -- 采用类似C语言的语法结构。复杂的特性全用table搞定,简单易学。
               -- 只有200多K,还有比这更小的吗?

1.2 lua的安装

lua可以说是非常简单易学了。首先是安装。

它的安装包只有200多K,在windows下可以直接下载包含二进制可执行程序的安装包。解压后得到:

  • lua53.dll
  • lua53.exe
  • luac53.exe
  • wlua53.exe

只有这4个文件,将这个目录配置到系统path中安装就算完成了。

1.3 执行lua脚本文件

lua使用.lua扩展名的文件来保存源码。可以在CMD中使用如下命令来执行.lua脚本文件:

1
lua53 test.lua      

.lua文件不需要再编译为特定的可执行文件。直接执行源码文件就很快。

2. 基本语法

2.1 文件结构概览

目前来讲,由于只是初步使用,所以我的代码都写在一个文件中。

下面我将给出一个短小精悍的例子代码。麻雀虽小但五脏俱全,这个例子代码中几乎包含了初步使用lua的所有内容。主要有:

  • 代码的文本风格
  • 变量定义
  • 函数定义
  • 字符串类型
  • 数值类型
  • 表与数组
  • if控制语句
  • for控制语句
  • 错误处理
  • 匿名函数

例子代码:

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
-- this is a sample code        
num = 1.34      
msg = "this is a test message."     
msg2 = 'this is another message.'       
msg3 = [[       
this is the first line.     
this is the second line.        
]]      

myTable = {     
        [1]             = 3.1415926,        
        ["name"]        = "table1",     
}       

-- myTable's member function        
function myTable.print()        

        -- print the table      
        print("num=" .. myTable[1] .. ", name=" .. myTable.name)        
end     

-- error catch      
if not pcall(       
                function()      

                        local x = 0     
                        msg = doSomeThing()     
                end     
        ) then      

        --error     
        print("this program is error.")     
        return      
end     

-- loop     
for k, v in ipairs(myTable) do      

        print("key=" .. k)      
        print("value=" .. v)        
end     

2.2 控制语句

2.2.1 分支

IF 语句

直接上例子比较直观

1
2
3
4
5
6
7
if x > y then   
    print("X > Y")  
elseif x == y then  
    print("X == Y") 
else    
    print("X < Y")  
end 

SWITCH语句

lua中并没有switch语句,想要实现类似的功能,可以在table中保存分支。

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
-- 分支函数定义   
function func1(n)   
    print("func1 " .. n)    
end 
function func2(n)   
    print("func2 " .. n)    
end 
function func3(n)   
    print("func3 " .. n)    
end 

local mySwitch = {  
    [1] = func1,    -- 分支1  
    [3] = func2,    -- 分支2  
    [68] = func3,   -- 分支3  
}   

local n = 3 
-- 取得分支对应的函数    
local funcX = mySwitch[n]   
-- 调用函数 
funcX(699)  
2.2.2 循环

WHILE语句

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
x = 1   
while x < 10 do 
    print(x)    
    if x == 4 then  
        break   
    end 
    x = x + 1   
end 

repeat  
    print(x)    
    if x == 8 then  
        break   
    end 
    x = x + 1   
until x > 20    

FOR语句

1
2
3
4
-- for i = 起始值, 终止值, 增幅 do  
for i = 1, 10, 2 do 
    print(i)    
end 

2.3 lua中的特殊语法

lua的大部分语法与类C语言相似,很容易就能掌握基本的语法。所以不再赘述,这里我主要说一下lua里区别于其它语言的特殊语法。

2.3.1 字符串定义

lua中有三种定义字符串的方式。其中值得一提的是使用如下方式定义多行字符串,非常方便有没有:

1
2
3
4
msg = [[    
This is the first line. 
This is the second line.    
]]  
2.3.2 数组与表

lua中的数组就是表。其它各种复杂的结构也都是通过表来实现的。表的索引可以是数字或者字符串类型。也可以不指定索引,不指定将默认使用从1开始的数组,注意不是从0开始的。访问的时候可以采用数组或者类成员风格:

1
2
3
4
5
6
7
myTable = { 
        [-100]          = 100,  
        ["name"]        = "Hakurei Youmu",  
        [0]             = "Hakurei",    
        [1]             = "Youmu",  
        ["score"]       = 98    
}   

可以看出索引可以随意指定,虽然默认从1开始,但也可以指定为负值。访问的时候也很方便:

1
2
3
4
myTable[-100]   
myTable["name"] 
myTable.name    
myTable.score   

在table中,当然是可以嵌套table的,并且各种类型的索引和值可以随意嵌套。

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
myTable = { 
    [3] = {123, 234, 678},  
    [4] = {"hello", "Tom"}, 
    ["9006"] = {22, 34, "699"}  
}   

print(myTable[4][1])    
print(myTable["9006"][3])   

-- 输出   
-- hello    
-- 699  
2.3.3 多值表达式

lua支持一种使用,来进行连接的多值表达式。除了表定义里不能用,它可以用在其它很多表达式可以出现的地方。例如下面几种场景:

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
-- 同时给多个变量赋值    
x, y, z = 100, 20, "3456"   

function func1()    

        --函数可以返回多个值 
        return 1, 2, "3"    
end 

-- 同时接受多个返回值    
x, y, z = func1()   

print(x, y, z)  

-- 输出为:1        2       3   

是不是感觉很神奇。多值表达式还可以用来交换两个变量的值:

1
2
-- 交换x和y的值  
x, y = y, x 

由于lua先计算=后面的值,再赋给左边的变量。所以这个奇特的用法就这样成立了。

2.3.4 运算符与字符串拼接

lua中字符串拼接使用专用操作符..,而+-*/%^都会十分耿直的进行数值的加减乘除等运算。所以有了下面的奇特用法:

1
2
3
4
5
6
print(1 + "124")    
print("1245" + "6453")  
print("12" - 88)    
print(49 % "2") 
print("9" * "9")    
print("2" ^ 5)  

上面的所有语句都成立,并且不像javaScript语句中那样混乱。这里的运算符一定是执行数值运算, 而与字符串可以说是毫无瓜葛,不会出现两边混淆,搞不清结果的问题。

2.4 编写多个模块

有时候我们写的程序比较大,会自然的想到去分成多个模块。
此时可以把每个模块写到一个文件中,其它文件可以通过包含这个模块文件来使用这个文件中定义的数据和函数。

类似于C/C++的include和Java的import,lua中使用require关键字来包含一个模块文件:

1
require "模块名"       

使用示例,要在test.lua中引用abc.lua模块。

目录如下:

1
2
3
test.lua        
mylib       
    |_abc.lua   

mylib/abc.lua

1
2
X = 123     

test.lua

1
2
require "mylib.abc" 或者
require "mylib/abc"

注意文件夹层次结构使用 . (点)或者 / 来表示。

如果执行test.lua文件,则abc.lua文件会先被执行一遍。

3. lua与命令行的无缝连接

3.1 lua调用CMD命令

1
2
-- cmd为cmd命令行       
os.execute(cmd)     

3.2 CMD调用lua文件

由于安装lua的时候,已经将可执行文件路径加入到系统path中了。所以再cmd环境中可以直接调用:

1
lua53 test.lua      

3.3 管理控制台输入与输出

直接向控制台打印字符,和从控制台读入字符是很容易的:

1
2
3
4
5
-- 往标准输出中打印字符       
print("Hello world!")       

-- 从标准输入中读入一行文字     
lineStr = io.read()     

3.4 lua嵌入宿主CMD

当lua嵌入到cmd中执行的时候,两者是无缝配合的。我们完全不需要关心诸如输入输出之类的问题,

既然说是嵌入,那就意味着程序是如下一种工作模式:

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
// 从系统控制台执行CMD命令        
c:> zcmd        

// zcmd.bat或者zcmd.cmd开始执行里面的内容      

// zcmd内部使用lua53命令调用lua文件       
lua53 myCmd.lua     

// myCmd.lua执行各种复杂的逻辑处理     
此时的输入输出都通过一开始的系统控制台进行       

// myCmd.lua中通过os.execute(anotherCmd)来执行CMD命令       
调用系统命令实现我们想要的功能     

// 退出并返回到控制台        
c:>     

之所以要把lua嵌入CMD里执行,是因为Windows Bat语言的语法难以掌握并且也不是很方便。编写复杂的逻辑时十分费力。而且它不跨平台,我如果想在linux中做一个同样功能的批处理小程序,就几乎要重新所有代码。

而lua编写复杂的逻辑时,与类C语言接近又比它们简洁明了,可以说是游刃有余。即使我想换一个平台运行,也十分容易修改。

3.5 示例代码

%PATH%/zcmd.cmd

1
lua53 %LUA_PATH%\lib\zcmd.lua       

%LUA_HOME%/lib/zcmd.lua

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
-- this program is to execute the cmd I usally use.     
print()     
print("Please select the commond to execute:")      
print()     

-- the command      
cmdTable = {        
        "mvn archetype:generate -DarchetypeCatalog=local",      
        "mvn clean install",        
        "exit"      
}       

-- print the command        
--os.execute("color 6") --yellow        
for i, cmd in ipairs(cmdTable) do       
        print(i .. "-> " .. cmd)        
end     
--os.execute("color 7") --white     

-- select the command       
cmdIndex = 0;       
print()     
print("Command number:")        
while not pcall(        
                -- read a number from console       
                function()      
                        cmdIndex = tonumber(io.read())      
                        assert(cmdIndex >= 1 and cmdIndex <= #cmdTable)     
                end     
        ) do        
        print("Please input a number(1 to " .. #cmdTable .. "):")       
end     

-- if exit      
if cmdIndex == #cmdTable then       
        return      
end     

-- execute the command      
cmd = cmdTable[cmdIndex]        
print("Now execute : " .. cmd)      
if not pcall(       
                function()      
                        os.execute(cmd)     
                end     
        ) then      
        -- command execute error        
        print("Execute unsuccessful.")      
        return      
end     

-- finally and exit     
print("Execute finished.")      

4. lua语言学习

请认准lua官方网站:

http://www.lua.org/