转自:https://zybuluo.com/lisaisacat/note/636399  谢谢

Lua 基础简明教程

脚本开发


 

目录

 

注释

写一个程序,总是少不了注释的。 
在Lua中,你可以使用单行注释和多行注释。 
单行注释中,连续两个减号"--"表示注释的开始,一直延续到行末为止。相当于C++语言中的"//"。 
多行注释中,由"--[["表示注释开始,并且一直延续到"]]"为止。这种注释相当于C语言中的"/**/"。在注释当中,"[["和"]]"是可以嵌套的。

 

Lua 编程

经典的"Hello world"的程序总是被用来开始介绍一种语言。在Lua中,写一个这样的程序很简单:

 
  1. print("Hello world")

在Lua中,语句之间可以用分号""隔开,也可以用空白隔开。一般来说,如果多个语句写在同一行的话,建议总是用分号隔开。 
Lua 有好几种程序控制语句,如: 
条件控制: if 条件 then … elseif 条件 then … else … end 
While循环: while 条件 do … end 
Repeat循环: repeat … until 条件 
For循环: for 变量 = 初值,终点值,步进 do … end 
For循环: for 变量1,变量2,… ,变量N in表或枚举函数 do … end

注意一下,for的循环变量总是只作用于for的局部变量,你也可以省略步进值,这时候,for循环会使用1作为步进值。 
你可以用break来中止一个循环。

如果你有程序设计的基础,比如你学过Basic,C之类的,你会觉得Lua也不难。但Lua有几个地方是明显不同于这些程序设计语言的,所以请特别注意。

 

语句块

语句块在C++中是用"{"和"}"括起来的,在Lua中,它是用do 和 end 括起来的。比如:

 
  1. do print("Hello") end

你可以在 函数 中和 语句块 中定局部变量。

 

赋值语句

赋值语句在Lua被强化了。它可以同时给多个变量赋值。 
例如:

 
  1. a,b,c,d=1,2,3,4

甚至是:

 
  1. a,b=b,a -- 多么方便的交换变量功能啊。

在默认情况下,变量总是认为是全局的。假如你要定义局部变量,则在第一次赋值的时候,需要用local说明。比如:

 
  1. local a,b,c = 1,2,3 -- a,b,c都是局部变量
 

循环语句

  1. while 循环:while 条件 do … end
  2. repeat 循环:repeat … until 条件
  3. for 循环:for 变量 = 初值,终点值,步进 do … end
  4. for 循环:for 变量1,变量2,… ,变量N in表或枚举函数 do … end

while 练习

 
  1. my_table = {1,2,3}
  2. local index = 1 -- 注意: table 中的索引从1开始
  3. while my_table[index] do -- 只要条件返回True,就一直执行循环
  4. print(my_table[index])
  5. index = index +1 -- Lua中没有i++ 的写法,所以只能用这种写法
  6. end
  7. -- 输出 1
  8. -- 2
  9. -- 3

repeat 练习(相当于其他语言中的do...while)

 
  1. local snum = 1 --起始值
  2. repeat
  3. print("snum is "..snum)
  4. snum = snum + 1
  5. until snum == 4 --当snum 等于 4 时 跳出循环
  6. --输出:
  7. --snum is 1
  8. --snum is 2
  9. --snum is 3

for 循环练习1

 
  1. for i = 1, #my_table do --#my_table 表示取表的长度,上边定义了长度为3
  2. print(my_table[i])
  3. end

--for 循环练习2

 
  1. for i=1,10,2 do -- 这里i=1表示起始值, 10 表示最大值, 2表示步进值(可以没有,默认值为1,也就是其他语言里的i++)
  2. print(i)
  3. end

注意一下,for的循环变量总是只作用于for的局部变量,你也可以省略步进值,这时候,for循环会使用 1 作为步进值。 
可以用break来中止一个循环。

 

数值运算

和C语言一样,支持+, -, *, /。但Lua还多了一个"^"。这表示指数乘方运算。比如2^3 结果为8, 2^4结果为16。 
连接两个字符串,可以用".."运处符。如:

 
  1. "This a " .. "string." -- 等于 "this a string"
 

比较运算

< > <= >= == ~= 
分别表示 小于,大于,不大于,不小于,相等,不相等 
所有这些操作符总是返回 true 或 false。 
对于Table,Function和Userdata类型的数据,只有 == 和 ~=可以用。相等表示两个变量引用的是同一个数据。比如:

 
  1. a={1,2}
  2. b=a
  3. print(a==b, a~=b) -- true, false
  4. a={1,2}
  5. b={1,2}
  6. print(a==b, a~=b) -- false, true
 

逻辑运算

and, or, not

其中,and 和 or 与C语言区别特别大。 
在这里,请先记住,在Lua中,只有 false 和 nil 才计算为 false,其它任何数据都计算为 true0 也是 true! 
and 和 or 的运算结果不是 true和false,而是和它的两个操作数相关。 
a and b: 如果a为false,则返回a;否则返回b 
a or b: 如果 a 为true,则返回a;否则返回b 
举几个例子:

 
  1. print(4 and 5) --> 5
  2. print(nil and 13) --> nil
  3. print(false and 13) --> false
  4. print(4 or 5) --> 4
  5. print(false or 5) --> 5

在Lua中这是很有用的特性,也是比较令人混洧的特性。 
我们可以模拟C语言中的语句:

 
  1. x = a? b : c

在Lua中,可以写成:

 
  1. x = a and b or c

最有用的语句是:

 
  1. x = x or v

它相当于:

 
  1. if not x then x = v end
 

运算符优先级

从高到低顺序如下:

 
  1. ^
  2. not - (一元运算)
  3. * /
  4. + -
  5. ..(字符串连接)
  6. < > <= >= ~= ==
  7. and
  8. or
 

关键字

关键字是不能做为变量的。Lua的关键字不多,就以下几个:

 
  1. and break do else elseif
  2. end false for function if
  3. in local nil not or
  4. repeat return then true until while
 

变量类型

怎么确定一个变量是什么类型的呢?大家可以用type()函数来检查。Lua支持的类型有以下几种:

 

Nil 空值

所有没有使用过的变量,都是nil。nil既是值,又是类型。

 

Boolean 布尔值

true 或 false

 

Number 数值

在Lua里,数值相当于C语言的double

 

String 字符串

如果你愿意的话,字符串是可以包含'\0'字符的

 

Table 关系表类型

这个类型功能比较强大,我们在后面慢慢说。

 

Function 函数类型

不要怀疑,函数也是一种类型,也就是说,所有的函数,它本身就是一个变量。

 

Userdata

嗯,这个类型专门用来和Lua的宿主打交道的。宿主通常是用C和C++来编写的,在这种情况下,Userdata可以是宿主的任意数据类型,常用的有Struct和指针。

 

Thread 线程类型

在Lua中没有真正的线程。Lua中可以将一个函数分成几部份运行。如果感兴趣的话,可以去看看Lua的文档。

 

变量的定义

所有的语言,都要用到变量。在Lua中,不管你在什么地方使用变量,都不需要声明,并且所有的这些变量总是全局变量,除非,你在前面加上"local"。 
这一点要特别注意,因为你可能想在函数里使用局部变量,却忘了用local来说明。 
至于变量名字,它是大小写相关的。也就是说,A和a是两个不同的变量。 
定义一个变量的方法就是赋值。""操作就是用来赋值的 
我们一起来定义几种常用类型的变量吧。

 

Nil

正如前面所说的,没有使用过的变量的值,都是Nil。有时候我们也需要将一个变量清除,这时候,我们可以直接给变量赋以nil值。如:

 
  1. var1=nil -- 请注意 nil 一定要小写
 

Boolean

布尔值通常是用在进行条件判断的时候。 
布尔值有两种:true 和 false。在Lua中,只有false和nil才被计算为false,而所有任何其它类型的值,都是true。比如0,空串等等,都是true。不要被C语言的习惯所误导,0在Lua中的的确确是true。你也可以直接给一个变量赋以Boolean类型的值,如:

 
  1.     varboolean = true
 

Number

在Lua中,是没有整数类型的,也不需要。一般情况下,只要数值不是很大(比如不超过100,000,000,000,000),是不会产生舍入误差的。在很多 CPU 上,实数的运算并不比整数慢。 
实数的表示方法,同 C 语言类似,如:

 
  1. 4
  2. 0.4
  3. 4.57e-3
  4. 0.3e12
  5. 5e+20
 

String

字符串,总是一种非常常用的高级类型。在Lua中,你可以非常方便的定义很长很长的字符串。 
字符串在Lua中有几种方法来表示,最通用的方法,是用双引号或单引号来括起一个字符串的,如:

 
  1. "This is a string."

和C语言相同的,它支持一些转义字符,列表如下:

 
  1. \a bell
  2. \b back space
  3. \f form feed
  4. \n newline
  5. \r carriage return
  6. \t horizontal tab
  7. \v vertical tab
  8. \\ backslash
  9. \" double quote
  10. \' single quote
  11. \[ left square bracket
  12. \] right square bracket

由于这种字符串只能写在一行中,因此,不可避免的要用到转义字符。加入了转义字符的串,看起来实在是不敢恭维,比如:

 
  1.     "one line\nnext line\n\"in quotes\", 'in quotes'"

一大堆的"\"符号让人看起来很倒胃口。如果你与我有同感,那么,我们在Lua中,可以用另一种表示方法:用"[["和"]]"将多行的字符串括起来,如:

 
  1. page = [[
  2. <HTML>
  3.    <HEAD>
  4.      <TITLE>An HTML Page</TITLE>
  5.    </HEAD>
  6.    <BODY>
  7.      <A HREF="http://www.lua.org">Lua</A>
  8.      [[a text between double brackets]]
  9.    </BODY>
  10.  </HTML>
  11.  ]]

值得注意的是,在这种字符串中,如果含有单独使用的"[["或"]]"就仍然得用"\["或"\]"来避免歧义。当然,这种情况是极少会发生的。

 

Table

关系表类型,这是一个很强大的类型。我们可以把这个类型看作是一个数组。只是C语言的数组,只能用正整数来作索引;在Lua中,你可以用任意类型来作数组的索引,除了nil。同样,在C语言中,数组的内容只允许一种类型;在Lua中,你也可以用任意类型的值来作数组的内容,除了nil。

Table的定义很简单,它的主要特征是用"{"和"}"来括起一系列数据元素的。比如:

 
  1. T1 = {} -- 定义一个空表
  2. T1[1]=10 -- 然后我们就可以象C语言一样来使用它了。
  3. T1["John"]={Age=27, Gender="Male"}

这一句相当于:

 
  1. T1["John"]={} -- 必须先定义成一个表,还记得未定义的变量是nil类型吗
  2. T1["John"]["Age"]=27
  3. T1["John"]["Gender"]="Male"

当表的索引是字符串的时候,我们可以简写成:

 
  1. T1.John={}
  2. T1.John.Age=27
  3. T1.John.Gender="Male"

 
  1. T1.John{Age=27, Gender="Male"}

这是一个很强的特性。 
在定义表的时候,我们可以把所有的数据内容一起写在"{"和"}"之间,这样子是非常方便,而且很好看。比如,前面的T1的定义,我们可以这么写:

 
  1. T1=
  2.   {
  3.     10, -- 相当于 [1] = 10
  4.    [100] = 40,
  5.       John= -- 如果你原意,你还可以写成:["John"] =
  6.       {
  7.         Age=27, -- 如果你原意,你还可以写成:["Age"] =27
  8.         Gender=Male -- 如果你原意,你还可以写成:["Gender"] =Male
  9.       },
  10.       20 -- 相当于 [2] = 20
  11. }

看起来很漂亮,不是吗?我们在写的时候,需要注意三点: 
第一,所有元素之间,总是用逗号""隔开; 
第二,所有索引值都需要用"["和"]"括起来;如果是字符串,还可以去掉引号和中括号; 
第三,如果不写索引,则索引就会被认为是数字,并按顺序自动从1往后编; 
表类型的构造是如此的方便,以致于常常被人用来代替配置文件。是的,不用怀疑,它比ini文件要漂亮,并且强大的多。

 

Function

函数,在Lua中,函数的定义也很简单。典型的定义如下:

 
  1. function add(a,b) -- add 是函数名字,a和b是参数名字
  2. return a+b -- return 用来返回函数的运行结果
  3. end

请注意,return语言一定要写在end之前。假如你非要在中间放上一句return,那么请写成:do return end。 
还记得前面说过,函数也是变量类型吗?上面的函数定义,其实相当于:

 
  1. add = function (a,b) return a+b end

当你重新给add赋值时,它就不再表示这个函数了。你甚至可以赋给add任意数据,包括nil (这样,你就清除了add变量)。Function是不是很象C语言的函数指针呢? 
和C语言一样,Lua的函数可以接受可变参数个数,它同样是用"…"来定义的,比如:

 
  1. function sum (a,b,…)

如果想取得…所代表的参数,可以在函数中访问arg局部变量(表类型)得到。如

 
  1. sum(1,2,3,4)

则,在函数中,

 
  1. a = 1, b = 2, arg = {3, 4}

更可贵的是,它可以同时返回多个结果,比如:

 
  1. function s()
  2.   return 1,2,3,4
  3. end
  4. a,b,c,d = s() -- 此时,a = 1, b = 2, c = 3, d = 4

前面说过,表类型可以拥有任意类型的值,包括函数!因此,有一个很强大的特性是,拥有函数的表,哦,我想更恰当的应该说是对象吧。Lua可以使用面向对象编程了。不信?那我举例如下:

 
  1.     t =
  2.     {
  3.      Age = 27
  4.      add = function(self, n) self.Age = self.Age+n end
  5.     }
  6.     print(t.Age) -- 27
  7.     t.add(t, 10)
  8.     print(t.Age) -- 37

不过,t.add(t,10) 这一句实在是有点土对吧?没关系,在Lua中,你可以简写成:

 
  1. t:add(10) -- 相当于 t.add(t,10)

注意事项 
用触动精灵开发脚本时,一定要记得把封装函数写在调用前面,因为脚本是按照从上往下的顺序执行的,如果先调用而没有封装,就会报错。

2018.09.29 Lua的更多相关文章

  1. 2018.09.29 bzoj3166: [Heoi2013]Alo(01trie+双向链表)

    传送门 01trie经典题目. 我们可以通过计算每个数作为次小值时对答案的贡献. 显然对于每个iii需要求出一个包含a[i]a[i]a[i]且的区间[l,r][l,r][l,r]且区间所有值都小于a[ ...

  2. 2018.09.29 bzoj3885: Cow Rectangles(悬线法+二分)

    传送门 对于第一个问题,直接用悬线法求出最大的子矩阵面积,然后对于每一个能得到最大面积的矩阵,我们用二分法去掉四周的空白部分来更新第二个答案. 代码: #include<bits/stdc++. ...

  3. 2018.09.29 bzoj3039: 玉蟾宫(悬线法)

    传送门 悬线法的板子题. 悬线法只需要保存当期点向下最多多少个,把这个当成一条线,再处理出线绷直之后最多能向左右延展多少就行了. 代码: #include<bits/stdc++.h> # ...

  4. 2018.09.29 bzoj3156: 防御准备(斜率优化dp)

    传送门 斜率dp经典题目. 然而算斜率的时候并没有注意到下标的平方会爆int于是咕咕*2. 这道题我用了两个数组来表示状态. f[i]f[i]f[i]表示最后i个位置倒数第i个放木偶的最优值. g[i ...

  5. 2018.09.29 bzoj3675: [Apio2014]序列分割(斜率优化dp)

    传送门 斜率优化dp经典题目. 首先需要证明只要选择的K个断点是相同的,那么得到的答案也是相同的. 根据分治的思想,我们只需要证明有两个断点时成立,就能推出K个断点时成立. 我们设两个断点分成的三段连 ...

  6. http://www.blogjava.net/xzclog/archive/2011/09/29/359789.html

    http://www.blogjava.net/xzclog/archive/2011/09/29/359789.html http://bbs.csdn.net/topics/380187593

  7. 2018.09.22 上海大学技术分享 - An Introduction To Go Programming Language

    老实说笔者学习 Go 的时间并不长,积淀也不深厚,这次因缘巧合,同组的同事以前是上海大学的开源社区推动者之一,同时我们也抱着部分宣传公司和技术分享的意图,更进一步的,也是对所学做一个总结,所以拟定了这 ...

  8. Lean Data Innovation Sharing Salon(2018.09.15)

    时间:2018.09.15地点:北京国华投资大厦

  9. Artificial Intelligence Computing Conference(2018.09.12)

    时间:2018.09.12地点:北京国际饭店会议中心

随机推荐

  1. mint linux 18.3 遇到“已安装的 post-installation 脚本 返回了错误号 127 ”问题的解决

    From https://blog.csdn.net/ropai/article/details/27171687 ubuntu 14.04遇到“已安装的 post-installation 脚本 返 ...

  2. 如何解决vux不兼容安卓低版本问题

    最近做移动端H5页面用VUX来写UI组件这块.ios测试的时候没啥大问题,不过在4.4版本的华为手机上测试就崩了.接下来详细记述下崩的几个点. 第一:vux自带的提示框,在低版本安卓系统上全不是居中显 ...

  3. add-migration Build failed.

    >add-migration JczInfoDateTimeBuild failed. 1编译解决方案,看是否报错,不管哪个有错误都会迁移失败 2重启vs

  4. mysql 动态行转列

    表结果:create table user( id int , username ), create_time datetime, type int ) insert into user (`id`, ...

  5. C机器级移位,编码表示 无符号编码表示,有符号编码表示一般最常见的方式是补码

    C机器级移位,编码表示 无符号编码表示,有符号编码表示一般最常见的方式是补码  w位补码所能表示的值范围是 首先我们得心知 补码的最高有效位是符号位,当符号位位1是表示的是负值,当符号位是0是,表示的 ...

  6. 服务器上运行程序Out of memory 解决办法

    ****** 服务器上跑过程序经常能遇到out of memory 这个问题,下面是我经常在实验室碰到的解决方法. 1.使用命令nvidia-smi,看到GPU显存被占满: 2.尝试使用 ps aux ...

  7. java面试题复习(六)

    51.实现多线程的方法 一种是继承Thread类:另一种是实现Runnable接口.两种方式都要通过重写run()方法来定义线程的行为,推荐使用后者,因为Java中的继承是单继承,一个类有一个父类,如 ...

  8. 常用的js代码合集

    !function(util){ window.Utils = util(); }( function(){ //document_event_attributes var DEA = "d ...

  9. css 效果之转换

    在css3 中,有一个转换效果,也可以替代js,并且比 js 做得好,那就是转换,即transform 属性,只需要个这个属性加上值,就可以实现转化效果了;有三种值,平移(translate),旋转( ...

  10. 3.Telnet探测端口后怎么退出

    使用 'Ctrl' +  ' ] ' 一起按退出