lua语法教程
# 基础语法
## 视频教程
<div class="admonition">
<p class="title">Lua快速入门</p>
<iframe id="spjc" src="//player.bilibili.com/player.html?aid=291542005&bvid=BV1vf4y1L7Rb&cid=368202399&page=1" scrolling="no" border="0" frameborder="no" framespacing="0" allowfullscreen="true" width="100%"> </iframe>
<script type="text/javascript">
document.getElementById("spjc").style.height=document.getElementById("spjc").scrollWidth*0.76+"px";
</script>
</div>
> 学完入门教程后,可以继续学习[进阶教程](https://www.bilibili.com/video/BV1WR4y1E7ud)
## 文字版教程
### 初识Lua
Lua 是一种轻量小巧的脚本语言,它用标准C语言编写并以源代码形式开放。这意味着什么呢?这意味着Lua虚拟机可以**很方便的嵌入别的程序里**,从而为应用程序提供灵活的扩展和定制功能。而整个Lua虚拟机编译后仅仅一百余K,经过适当的裁剪还能做到更小,十分适合嵌入式的开发。
同时,在目前脚本引擎中,Lua的运行速度占有绝对优势。这些都决定了Lua是作为嵌入式脚本的最佳选择。
在我们编写代码之前,需要做一下准备,就是:**确保你输入标点符号时,用的不是中文输入法。**
--------
### 第一个 Lua 程序
几乎所有语言的第一行代码,都是输出`hello world`,本教程也不意外。
在`Lua`中,打印结果只需要使用`print`这个`函数`即可。同时,如果需要使用`函数`,只需要在函数名后加上双括号,同时传入你想传入的值即可。
所以,我们来执行下面的代码,打印出`hello world`吧!
```lua
print("hello world!")
```
--------
### 输出数据
上一部分,我们知道了,在`Lua`中,可以使用`print`函数来打印你想要得到的结果。
并且还知道了,`函数`是指可以实现某些功能的子程序,可以使用`函数名(参数)`来执行。
让我们试着输出一些其他东西吧!使用多个print函数,输出自己想输出的数据。
```lua
print("测试")
print("aabcdefg")
print("xxxxx","第二个参数","第三个参数")
```
--------
### 代码注释
代码`注释`就是在代码里,不会运行的部分。`注释`完全不会被运行。
这部分是为了在查看代码时,可以更好地立即现有代码含义用的。
我们可以用`--`开头,来写一段`单行注释`
也可以用`--[[`开头,`]]`结尾,写一段多行注释。
下面是注释的例子:
```lua
print("这段代码会运行")
--print("我被注释掉了,所以不会运行")
--[[
我是多行注释
不管我写多少行
都不会影响代码运行
]]
```
--------
## 变量
### number变量
`变量`,可以看作是一个桶,在里面装你想要装的内容。这些内容可以是Lua包含的所有合法类型。
例如:我想要新建一个桶,名叫bucket,在里面放入233这个数字,就可以像下面一样:
```lua
bucket = 233
```
让我们试着自己新建几个变量吧!
- 新建变量year,并将变量的值设置为1926
- 新建变量month,并将变量的值设置为8
- 新建变量day,并将变量的值设置为7
```lua
--新建三个变量,并赋值
year = 1926
month = 8
day = 7
--打印出三个变量的值
print(year,month,day)
```
--------
### 了解nil
`nil`类型表示没有任何有效值,只要是没有声明的值,它就是`nil`
比如我打印一个没有声明的值,便会输出`nil`:
```lua
ccc = 233
print(ccc)
print(aaa)
```
**这里需要你思考一下,运行以下代码,将会输出什么结果?**
```lua
a = 1
b = '2'
c = a
print(a,b,c,d)
```
--------
### 赋值语句
`赋值`是改变一个变量值的最基本的方法。
如下面一样,使用`等号`对`左边`的`变量`进行赋值
```lua
n = 2
n = 3
n = n + 1
b = n
```
`Lua`可以对多个变量同时赋值,变量用`逗号`分开,`赋值`语句`右边的值`会依次赋给`左边的变量`。
```lua
n = 1
a, b = 10, 2*n
```
当左右值的数量不一致时,Lua会进行下面的设定:
- 变量个数 > 值的个数:按变量个数补足nil
- 变量个数 < 值的个数:多余的值会被忽略
下面的例子可以展示这种设定:
```lua
a, b, c = 0, 1
print(a,b,c)
--输出0 1 nil
a, b = a+1, b+1, b+2
print(a,b)
--输出1 2
a, b, c = 0
print(a,b,c)
--输出0 nil nil
```
**这里需要你思考一下,运行以下代码,将会输出什么结果?**
```lua
a,b,c = 1,2,3
a,c = a+1,b
d = c,b
print(a,b,c,d)
```
--------
### 交换变量
这部分需要你自己完成一个任务:
已知下面的代码,并且已知`a`和`b`的值,请在交换他们的值,使打印输出`12 34`
```lua
a = 34
b = 12
--你需要在这里进行交换变量的操作
--提示:新建一个变量来存放临时的值
print(a,b)
```
--------
### 输出变量
我们已经知道了,在Lua中,可以使用print函数来打印你想要得到的结果。
同时在上一节,我们学会了新建变量和设置变量的值。
让我们试着输出某个变量吧!使用`print函数`,输出已知变量。 我们已知变量`num`为某个数字,试着输出它的值吧!
```lua
num = 123
--请补全代码,输出num的值
print(你要在这里填东西)
```
--------
### 算数运算符
运算符是一个特殊的符号,用于告诉解释器执行特定的数学或逻辑运算。
上一节中,新建的数字变量,我们称之为`number`类型的变量。
本节我们来学习使用`算术运算符`,如下所示:
```
+ 加法
- 减法
* 乘法
/ 除法
% 取余,求出除法的余数
^ 乘幂,计算次方
- 负号,取负值
```
我们可以通过以下实例来理解算术运算符的应用:
```lua
a = 21
b = 10
c = a + b
print('a + b 的值为 ', c )
c = a - b
print('a - b 的值为 ', c )
c = a * b
print('a * b 的值为 ', c )
c = a / b
print('a / b 的值为 ', c )
c = a % b
print('a % b 的值为 ', c )
c = a^2
print('a^2 的值为 ', c )
c = -a
print('-a 的值为 ', c )
c = a * (b - a)
print('a * (b - a) 的值为 ', c )
```
**你需要完成下面的任务:**
已知,一个长方体的长宽高分别为a、b、c(单位米),且这个物体重量为m(单位克)
请打印出物体的密度(单位g/m³)
注:密度计算公式 密度 = 质量 / 体积
```lua
a,b,c = 1,2,3 --长宽高
m = 10 --重量
--请打印出物体的密度
```
--------
## 字符串
### string类型变量
`字符串`(即`string`),就是一串文本数据,可以存储你要的文本。
在第二节中,`print`出的数据就是一个字符串。
Lua 语言中字符串可以使用以下三种方式来表示:
1. 单引号间的一串字符
2. 双引号间的一串字符
3. [[和]]间的一串字符
你可以参考下面的例子来深入理解:
```lua
--双引号间的一串字符
str1 = "Lua"
--单引号间的一串字符
str2 = 'Lua'
--[[和]]--间的一串字符
str3 = [[Lua]]
str4 = [[使用双括号时,甚至能包含换行数据
换行了
最后一行]]
--输出所有字符串
print(str1)
print(str2)
print(str3)
print(str4)
```
**接下来你需要完成下面的练习:**
新建三个变量`s1`、`s2`、`s3`
分别存入字符串数据:`str`、`abc`、`233`,使输出打印正确
```lua
--请在空白处补全代码
print("s1,s2,s3的值:",s1,s2,s3)
print("s1,s2,s3的类型:",type(s1),type(s2),type(s3))
```
--------
### 转义字符
在上一节中,我们学习了如何声明字符串。
但是我们有时候会遇到一些特殊的问题,如:**如何输出单引号和双引号?如何输出回车换行?**
也许我们可以用下面的方式简单规避,输出单引号时,声明字符串用双引号括起来,像下面这样
```lua
str = "'"
```
同理,输出双引号时,声明字符串用单引号括起来,像下面这样
```lua
str = '"'
```
但是,这样会出现一个问题:如何同时显示单引号和双引号?这里就需要`转义字符`登场了。
转义字符用于表示不能直接显示的字符,比如后退键、回车键、等。
以 `\` 开头的都是转义字符,下面时常用的转义字符格式:
转义字符|含义
-|-
\n|换行(LF),将当前位置移到下一行开头
\r|回车(CR),将当前位置移到本行开头
\\\\|反斜杠字符\
\'|单引号
\"|双引号
\0|空字符(NULL)
\ddd|1到3位八进制数所代表的任意字符
\xhh|1到2位十六进制所代表的任意字符
例如,如果我们想给str赋值一个单引号,一个双引号('"),那么我们可以这样写:
```lua
str = "\'\""
```
**下面需要你来完成一个简单的任务:**
新建一个变量`str`,给str赋值为
`ab\cd"ef'g\h]]`
并打印出来
```lua
str = --补全代码
print(str)
--输出应为ab\cd"ef'g\h]]
```
--------
### string拼接
字符串和字符串可以相加吗?可以!我们可以用拼接符号来将两个独立的字符串拼起来。
我们使用`..`来表示字符串拼接符号,如下面的示例代码:
```lua
print('abc'..'def')
str1 = '123'
str2 = '999'
print(str1..str2)
```
**下面你要完成这个任务:**
已知三个字符串变量`s1`、`s2`、`s3`
请将他们按顺序拼接起来,存入`all`,并使用print输出结果
```lua
s1,s2,s3 = "aaa","bbb","ccc"
all = --请补全代码
print(all)
```
--------
### number转string
上面一节学习了如何拼接字符串,这个方法固然很好用,但是有时候我们会遇到一个需求,那就是把`number`类型的变量和`string`类型的变量拼接起来,组成一个新的`string`
比如下面的变量`n`和`s`,如何拼接起来呢?
```lua
n = 123
s = 'm/s'
```
我们可以直接将`number`类型的变量`n`转换成`string`类型的值,这样就可以拼接了
使用`tostring(value)`函数即可实现这一操作:
```lua
n = 123
s = 'm/s'
result = tostring(n)..s
print(result)
```
**下面你要完成这个任务:**
已知三个变量`n1`、`s`、`n2`
然后将他们按顺序拼接起来,存入变量`result`,使输出结果正确
小提示:在某些情况下,Lua会自动将number类型转换成string类型
```lua
n1,s,n2 = 1,"abc",2
result = --请补全代码
print(result)
```
--------
### string转number
上面一节学习了如何将number转成string,这一节我们来学习如何将string转成number
比如下面的变量`s`,存储的内容是一个字符串,但是代表了一个数字,如何转成number再与n相加计算呢?
```lua
n = 123
s = '2333'
```
我们可以直接将`string`类型的变量`s`转换成`number`类型的值,这样就可以计算了
使用`tonumber(value)`函数即可实现这一操作:
```lua
n = 123
s = '2333'
result = tonumber(s) + n
print(result)
```
**下面你要完成这个任务:**
已知三个字符串变量`s1`、`s2`、`s3`,其内容均为纯数字
请计算他们的算术和,赋值给新建的变量`result`,使下面代码输出正确结果
```lua
s1,s2,s3 = "11","12","100"
result = --请补全代码
print(result)
```
--------
## 逻辑运算
### 布尔型和比较运算
布尔型(boolean)只有两个可选值:`true`(真) 和 `false`(假)
Lua 把 false 和 nil 看作是`false`,其他的都为true(包括0这个值,也是相当于`true`)
Lua 中也有许多的`关系运算符`,用于比较大小或比较是否相等,符号及其含义如下表:
|符号|含义|
|-|-|
|==|等于,检测两个值是否相等,相等返回 true,否则返回 false|
|~=|不等于,检测两个值是否相等,相等返回 false,否则返回 true|
|>|大于,如果左边的值大于右边的值,返回 true,否则返回 false|
|<|小于,如果左边的值大于右边的值,返回 false,否则返回 true|
|>=|大于等于,如果左边的值大于等于右边的值,返回 true,否则返回 false|
|<=|小于等于, 如果左边的值小于等于右边的值,返回 true,否则返回 false|
我们可以通过以下实例来更加透彻的理解关系运算符的应用:
```lua
a = 21
b = 10
print('==的结果',a==b)
print('~=的结果',a~=b)
print('>的结果',a>b)
print('<的结果',a<b)
print('>=的结果',a>=b)
print('<=的结果',a<=b)
```
**下面问题来了,运行以下代码,将会输出什么结果?请自行思考**
```lua
a = 1
b = '1'
c = a
d = 2
print(a == b)
print(c == a)
print(a ~= b)
print(d <= c)
```
--------
### 逻辑运算符
逻辑运算符基于布尔型的值来进行计算,并给出结果,下表列出了 Lua 语言中的常用逻辑运算符:
|符号|含义|
|-|-|
|and|逻辑与操作符。 若 A 为 false,则返回 A,否则返回 B|
|or|逻辑或操作符。 若 A 为 true,则返回 A,否则返回 B|
|not|逻辑非操作符。与逻辑运算结果相反,如果条件为 true,逻辑非为 false|
我们可以通过以下实例来更加透彻的理解逻辑运算符的应用:
```lua
print('true and false的结果',true and false)
print('true or false的结果',true or false)
print('true and true的结果',true and true)
print('false or false的结果',false or false)
print('not false的结果',not false)
print('123 and 345的结果',123 and 345)
print('nil and true的结果',nil and true)
```
**下面问题来了,运行以下代码,将会输出什么结果?**
```lua
a = 1
b = '1'
c = 0
print(a and b)
print(c or a)
print(not b)
print(d and c)
print(1 < 2 and 3 > 2)
```
--------
### 检验大小(自测题)
题目:如果已知number变量`n`,那么如果需要判断n是否符合下面的条件:
3<n≤10
以下四行判断代码,正确的是?
(返回true即表示变量`n`符合要求)
```lua
n = 1--这个数可能是任意数字
print(n > 10 or n <= 3)
print(n <= 10 or n > 3)
print(n < 3 and n >= 10)
print(n <= 10 or n > 3)
```
--------
## 分支判断
### 条件判断
上面一节学习了布尔类型,那么这个需要用到哪里呢?我们需要用它来进行某些判断。
在Lua中,可以使用`if`语句来进行判断,如下面所举例的代码,可以判断`n是否为小于10的数`:
```lua
n = 5
if n < 10 then
print('n小于10')
end
```
我们整理一下,实际上if语句就是如下结构:
```lua
if 条件 then
符合条件的代码
end
```
**下面是你需要完成的事:**
已知变量`n`,请判断`n`是否为奇数,如果是,请给`n`的值加上1
如果你觉得有难度,请查看下面的提示:
- 求出`n`除以2的余数:n % 2
- 给`n`的值加上1:n = n + 1
```lua
--已知一个number变量n
n = 5 --这个数字是几都有可能
print("n在判断前的值",n)
if 你的条件 then
要做的事
end
print("n在判断后的值",n)
```
--------
### 多条件判断
上面一节学习了简单的if语句写法,这一节我们来学习多条件分支语句
在Lua中,可以使用`if`语句来进行判断,同时可以使用`else`语句,表示多个分支判断
```lua
if 条件1 then
满足条件1
elseif 条件2 then
不满足条件1,但是满足条件2
else
前面条件全都不满足
end
```
举个例子,比如有一个`数字n`:
- 当它大于等于0、小于5时,输出`太小`,
- 当它大于等于5、小于10时,输出`适中`,
- 当它大于等于10时,输出`太大`,
那么代码就像如下这样:
```lua
n = 1--更改这个数多运行几次试试
if n >= 0 and n < 5 then
print('太小')
elseif n >= 5 and n < 10 then
print('适中')
elseif n >= 10 then
print('太大')
end
```
注意:`else`和`elseif`都是可选的,可有可无,但是`end`不能省略
**下面是你需要完成的事:**
已知变量`n`,请判断`n`是否为奇数,
- 如果是,请给`n`的值加上1
- 如果不是,请将`n`的值改为原来的两倍
```lua
--已知一个number变量n
n = 5 --这个数字是几都有可能
print("n在判断前的值",n)
if 你的条件 then
要做的事
else
要做的事
end
print("n在判断后的值",n)
```
--------
## 跨文件调用
在编写代码时,随着逻辑逐渐复杂,我们的代码量也会变大。虽然有`函数`可以把一部分代码逻辑封装起来,但是所有代码都放到一个文件里,显然也不是个好办法。
所以我们需要将一些代码放到不同文件中,通过文件来区分这些代码的功能。
比如我们有下面这个函数:
```lua
---函数功能:
-- 生成从1-max的table
-- @输入值:table的最大值
-- @返回: table结果
-- @例子: local list = getNumberList(10)
function getNumberList(max)
local t = {}
for i=1,max do
table.insert(t,i)
end
return t
end
```
我们新建一个文件叫`tools.lua`,把这个函数放进去,现在,整个文件如下面这样:
`tools.lua`
```lua
---函数功能:
-- 生成从1-max的table
-- @输入值:table的最大值
-- @返回: table结果
-- @例子: local list = getNumberList(10)
local function getNumberList(max)
local t = {}
for i=1,max do
table.insert(t,i)
end
return t
end
--手动返回一个table,包含了上面的函数
return {
getNumberList = getNumberList,
}
```
现在,我们封装的这个函数就能在其他文件里被调用了,具体代码如下:
```lua
--引用tools.lua文件,并加载
local tool = require("tools")
local list = tool.getNumberList(12)
```
当调用了`require`接口后,Lua虚拟机会自动加载你调用的文件,`执行文件的内容`,然后`返回你文件里return的结果`。
为了更好地理解这段话,我们可以看下面两个文件,其中run.lua是被运行的那个入口文件
`test.lua`
```lua
--以便一会儿返回使用的table
local temp = {}
--把全局变量a更改了
a = 1
--local变量无法被外部调用
--但是可以在文件内被调用
local b = 2
--文件在被require的时候,会被执行
--把全局变量c更改了
c = a + b
--使函数在table里
function temp.addB()
--文件内部可以调用变量b
b = b + 1
return b
end
--返回table
return temp
```
`run.lua`
```lua
local test = require("test")
print(a)--输出1
print(b)--输出nil,因为b是local变量
print(c)--输出3
print(test.addB())--输出3
print(test.addB())--输出4
print(test.addB())--输出5
```
同时,每个文件最多只会被`require`一次,如果有多个`require`,只有第一次会执行
## 待添加
- table -> sort排序
- string -> 正则、gsub、find、match
- 迭代器 for xx in xx 、string.gmatch
- 元表
- coroutine
↓各种接口↓
- math库
- os库
- io库
- 位运算 (>> <<)
- 杂项接口
- debug库
<script>
window.onload = function(){
//在代码块附近加上快速测试代码链接
$("pre").each(function () {
if($(this).text().indexOf("print") >= 0)
$(this).before('<a class="run-code-btn" href="https://wiki.luatos.com/_static/luatos-emulator/lua.html?'+escape($(this).text())+'" target="_blank">点我快速测试下面的代码</a>');
});
}
</script>