Lua基础语法讲解

Lua是什么?

Lua 是一种轻量小巧的脚本语言,用标准C语言编写并以源代码形式开放, 其设计目的是为了嵌入应用程序中,从而为应用程序提供灵活的扩展和定制功能。

Lua 是巴西里约热内卢天主教大学(Pontifical Catholic University of Rio de Janeiro)里的一个研究小组,由Roberto Ierusalimschy、Waldemar Celes 和 Luiz Henrique de Figueiredo所组成并于1993年开发。

设计目的

其设计目的是为了嵌入应用程序中,从而为应用程序提供灵活的扩展和定制功能。

Lua 特性

  • 轻量级: 它用标准C语言编写并以源代码形式开放,编译后仅仅一百余K,可以很方便的嵌入别的程序里。
  • 可扩展: Lua提供了非常易于使用的扩展接口和机制:由宿主语言(通常是C或C++)提供这些功能,Lua可以使用它们,就像是本来就内置的功能一样。
  • 其它特性:
    • 支持面向过程(procedure-oriented)编程和函数式编程(functional programming);
    • 自动内存管理;只提供了一种通用类型的表(table),用它可以实现数组,哈希表,集合,对象;
    • 语言内置模式匹配;闭包(closure);函数也可以看做一个值;提供多线程(协同进程,并非操作系统所支持的线程)支持;
    • 通过闭包和table可以很方便地支持面向对象编程所需要的一些关键机制,比如数据抽象,虚函数,继承和重载等。

Lua 基本语法

Lua 学习起来非常简单,我们可以创建第一个 Lua 程序!

交互式编程

Lua 提供了交互式编程模式。我们可以在命令行中输入程序并立即查看效果。

Lua 交互式编程模式可以通过命令 lua -i 或 lua 来启用:

$ lua -i

$ Lua 5.1.4 Copyright (C) 1994-2008 Lua.org, PUC-Rio

>

在命令行中,输入以下命令:

> print("my name is jack lee")

接着我们按下回车键,输出结果如下:

> print("my name is jack lee")

my name is jack lee

脚本式编程

我们可以将 Lua 程序代码编写到一个以 lua 结尾的文件,并执行,该模式称为脚本式编程,如我们将如下代码存储在名为 name.lua 的脚本文件中,并且将脚本放在D:盘

print("my name is jack!")

print("welcome learn lua follow teacher li!")

使用 lua 名执行以上脚本,输出打印结果

lua d:\Lua\name.lua

注释

单行注释

两个减号是单行注释:

--

多行注释

--[[

多行注释

多行注释

--]]

变量,函数命名规范

标示符表示一个变量,函数或其他定义项,命名规范以一个字母 A 到 Z 或 a 到 z 或下划线 _后加上字母,下划线 _数字(0到9)。建议不要使用下划线加大写字母的标示符,因为Lua的保留字也是这样的。

一般约定,以下划线开头连接一串大写字母的名字(比如 _VERSION)被保留用于 Lua 内部全局变量。

Lua 不允许使用特殊字符如 @, $, 和 % 来定义成员名。 Lua 是一个区分大小写的编程语言。因此在 Lua 中 Run 与 run 是两个不同的标示符。以下列出了一些正确的标示符:

mohd zara abc move_name a_123

myname50 _temp j a23b9 retVal

关键词

以下列出了 Lua 的保留关键字。保留关键字不能作为常量或变量或其他用户自定义标示符:注:(以下关键字后续会详细讲解)

and

break

do

else

elseif

end

false

for

function

if

in

local

nil

not

or

repeat

return

then

true

until

while

全局变量

在默认情况下,变量总是认为是全局的。

全局变量不需要声明,给一个变量赋值后即创建了这个全局变量,访问一个没有初始化的全局变量也不会出错,只不过得到的结果是:nil。

> print(b)

nil

> b=10

> print(b)

10

>

你可以设置全局变量为空,只需要将变量赋值为nil。

b = nil

print(b) --> nil

这样变量b就好像从没被使用过一样。换句话说, 当且仅当一个变量不等于nil时,这个变量即存在。

Lua 数据类型

Lua是动态类型语言,变量不要类型定义,只需要为变量赋值。 值可以存储在变量中,作为参数传递或结果返回。

Lua中有8个基本类型分别为:nil、boolean、number、string、userdata、function、thread和table。 (注:以下数据类型后续做详细讲解)

数据类型

描述

nil

表示一个无效值(在条件表达式中相当于false)。

boolean

包含两个值:false和true。

number

表示双精度类型的实浮点数

string

字符串由一对双引号或单引号来表示 "" \'\'

function

函数

userdata

表示任意存储在变量中的C数据结构

thread

表示执行的独立线程,用于执行协同程序

table

Lua 中的表(table)其实是一个"关联数组",数组的索引可以是数字或者是字符串。在 Lua 里,table 的创建是通过"构造表达式"来完成,最简单构造表达式是{},用来创建一个空表。

我们可以使用type函数测试给定变量或者值的类型:

在sublime编辑器中写下以下代码, 按Ctrl+B 编译。

_str="I am str"

_number=10.116

_bo=false

print(type(str))

print(type(_number))

print(type(_bo))

数据类型具体分析:

nil(空)

nil 类型表示一种没有任何有效值,它只有一个值 -- nil,例如打印一个没有赋值的变量,便会输出一个 nil 值:

> print(type(a))

nil

boolean(布尔)

boolean 类型只有两个可选值:true(真) 和 false(假),Lua 把 false 和 nil 看作是"假",其他的都为"真"

number(数字)

Lua 默认只有一种 number 类型 -- double(双精度)类型,以下几种写法都被看作是 number

print(type(2))

print(type(2.2))

print(type(0.2))

string(字符串)字符串由一对双引号或单引号来表示。

string1 = "this is string1"

string2 = \'this is string2\'

也可以用 2 个方括号 "[ [ ] ]" 来表示"一块"字符串。

_str2=[[my name is jack!]]

print(_str2)

在对一个数字字符串上进行算术操作时,Lua 会尝试将这个数字字符串转成一个数字:

print("1"+5) --6

print("1"+"6") --7

print("3+7") -- "3+7"

关于字符串拼接,使用.. 对字符串进行拼接

value=11

print("value="..value) --value=11

使用 #(井号)来计算字符串的长度,放在字符串前面,如下实例:

mail = "ukraine_lee@163.com"

print(#mail)

--19

Table(表)

在 Lua 里,table 的创建是通过"构造表达式"来完成,最简单构造表达式是大括号{},用来创建一个空表。也可以在表里添加一些数据,直接初始化表:

-- 创建一个空的 table

local tbl1 = {}

-- 直接初始表

local tbl2 = {"apple", "pear", "orange", "grape"} --苹果,梨,橙子,葡萄

local tbl2={X=3,y=4} --指定键值初始化 X,Y是键,值是3,4

Lua 中的表(table)其实是一个"关联数组",数组的索引可以是数字或者是字符串。(类似字典)

_table_1={}

_table_1["str_key1"]="str_value"

_table_1["str_key2"]=2

nub_key1=1

_table_1[nub_key1]="value1"

nub_key2=2

_table_1[nub_key2]=13

_table_1[nub_key2]=_table_1[nub_key2]+1

for k,v in pairs(_table_1) do

print(k.."===="..v)

end

不同于其他语言的数组把 0 作为数组的初始索引,在 Lua 里表的默认初始索引一般以 1 开始。

local tbl = {"apple", "pear", "orange", "grape"}

for key, val in pairs(tbl) do

print("Key", key)

end

-- 1 2 3 4

table 不会固定长度大小,有新数据添加时 table 长度会自动增长,没初始的 table 都是 nil。

_table = {}

for i = 1, 10 do

_table[i] = i

end

-- for k,v in pairs(_table) do

-- print(k,v)

-- end

_table["key"] = "val"

print(_table["key"])

print(_table["none"])

for k,v in pairs(_table) do

print(k,v)

end

表函数的定义和使用:

tab={x=2,y=3}

function tab:setValue(m_x,m_y) --注意定义的时候使用了:冒号

tab.x=m_x

tab.y=m_y

end

tab:setValue(5,6) --注意,在调用的时候也必须和定义时一致使用冒号。

print(tab.x,tab.y)

function(函数)

函数的基本语法:

function function_name(n_value)

return n_value+1

end

print(function_name(7))

函数还可以像下面这样存在一个变量里:

function function_name(n_value)

return n_value+1

end

print(function_name(7))

func_self=function_name

print(func_self(5))

function 可以以匿名函数(anonymous function)的方式通过参数传递:

--首先写一个函数 有个2个参数 1是表 2是函数 --遍历表 取出键值

--打印调用func将 键值作为参数传递进func

function anonymous(tab,func)

for k,v in pairs(tab) do

print(func(k,v))

end

end

--调用anonymous 1参传入表,2参是匿名函数并且有执行内容,--内容是返回_k _v 注--意函数结尾需要有end

_table={key1="value1",key2="value2"}

anonymous(_table,function(_k,_v)

return _k,_v

end)

thread(线程)

在 Lua 里,最主要的线程是协同程序(coroutine)。拥有自己独立的栈、局部变量和指令指针,可以跟其他协同程序共享全局变量和其他大部分东西。

线程跟协程的区别:线程可以同时多个运行,而协程任意时刻只能运行一个,并且处于运行状态的协程只有被挂起(suspend)时才会暂停。

userdata(自定义类型)

userdata 是一种用户自定义数据,用于表示一种由应用程序或 C/C++ 语言库所创建的类型,可以将任意 C/C++ 的任意数据类型的数据(通常是 struct 和 指针)存储到 Lua 变量中调用。(简单来说就是在LUA中用userdata表示其他语言的数据类型)

Lua 变量

变量在使用前,必须在代码中进行声明,即创建该变量,Lua 中的变量全是全局变量,那怕是语句块或是函数里,除非用 local 显式声明为局部变量,

局部变量的作用域为从声明位置开始到所在语句块结束,变量的默认值均为 nil。

variable_1=1 --全局

local variable_2 = 2 --局部

function function_name()

variable_3=3 --全局

local variable_4 = 4 --局部

return variable_3+variable_2--(注意 variable_2是在外面声明的局部变量,本质也是全局的)

end

print(function_name())

print("variable_3="..variable_3)

print("variable_4=",variable_4)-- 注意不能使用".."连接一个空值

赋值语句

赋值是改变一个变量的值和改变表域的最基本的方法。

value=1

strValue="str"

value_2=value+2

print(strValue)

---------------------------------------------------------

_table={n="n_vale",m="m_value"}

print(_table.n)

_table.n=11

print(_table.n)

Lua 循环

很多情况下我们需要做一些有规律性的重复操作,因此在程序中就需要重复执行某些语句。

一组被重复执行的语句称之为循环体,能否继续重复,决定循环的终止条件。

循环结构是在一定条件下反复执行某段程序的流程结构,被反复执行的程序被称为循环体。

循环语句是由循环体及循环的终止条件两部分组成的。

while 循环

Lua 编程语言中 while 循环语句在判断条件为 true 时会重复执行循环体语句。

语法

Lua 编程语言中 while 循环语法:(注意不同于C# 语句没有大括号)

while(condition)

do

statements

end

statements(循环体语句) 可以是一条或多条语句,condition(条件) 可以是任意表达式,在 condition(条件) 为 true 时执

实例:

a=1

while( a < 5 )

do

print("a 的值为:", a)

a = a+1

end

Lua for 循环

Lua 编程语言中 for 循环语句可以重复执行指定语句,重复次数可在 for 语句中控制。

Lua 编程语言中 for语句有两大类:(注意与C#的for 循环有较明显区别)

第一种:数值for循环

for var=exp1,exp2,exp3 do

<执行体>

end

var从exp1变化到exp2,每次变化以exp3为步长递增var,并执行一次"执行体"。exp3是可选的,如果不指定,默认为1。

实例:

for i=1,5 do

print(i)

end

---------------------------------------------------

function function_name(x)

return x*2

end

for i=1,function_name(3) do

print(i)

end

第二种:泛型for循环

泛型for循环通过一个迭代器函数来遍历所有值

在lua中pairs与ipairs两个迭代器的用法相近,但有一点是不一样的:

pairs可以遍历表中所有的key,包含索引,和自定义类型key

ipairs仅可以遍历出具备索引的值

_table2={"Suanday","Monday"}

_table2["ukey"]="uvalue" --键值都是字符串

intkey=8

_table2[intkey]="uvalue" --键是number 值是字符串

for k,v in ipairs(_table2) do

print(k,v)

end

输出结果是 (table2 中仅具备索引的2个值被输出了)

-- 1 Suanday

-- 2 Monday

for k,v in pairs(_table2) do

print(k,v)

end

输出结果是(所有的键值均被输出)

--1 Suanday

--2 Monday

--ukey uvalue

--8 uvalue

Lua break 语句

Lua 编程语言 break 语句插入在循环体中,用于退出当前循环或语句,并开始脚本执行紧接着的语句。

如果你使用循环嵌套,break语句将停止最内层循环的执行,并开始执行的外层的循环语句。

a=1

while(a<6)

do

print(a)

a=a+1

if(a>3)

then

break

end --注意if语句需要关键字 then和end

end --这个 end 是while 语句的结束

无限循环

在循环体中如果条件永远为 true 循环语句就会永远执行下去,以下以 while 循环为例:

while( true )

do

print("循环将永远执行下去")

end

Luaif 语句

Lua if 语句 由一个布尔表达式作为条件判断,其后紧跟其他语句组成。

Lua if 语句语法格式如下:

if(布尔表达式)

then

--[ 在布尔表达式为 true 时执行的语句 --]

end

a=1

if(a>0)

then

a=a+1

print(a)

end

if...else 语句

Lua if 语句可以与 else 语句搭配使用, 在 if 条件表达式为 false 时执行 else 语句代码块。

Lua if...else 语句语法格式如下:

if(布尔表达式)

then

--[ 布尔表达式为 true 时执行该语句块 --]

else

--[ 布尔表达式为 false 时执行该语句块 --]

end

if...elseif...else 语句

Lua if 语句可以与 elseif...else 语句搭配使用, 在 if 条件表达式为 false 时执行 elseif...else 语句代码块,用于检测多个条件语句。

Lua if...elseif...else 语句语法格式如下:

if( 布尔表达式 1)

then

--[ 在布尔表达式 1 为 true 时执行该语句块 --]

elseif( 布尔表达式 2)

then

--[ 在布尔表达式 2 为 true 时执行该语句块 --]

elseif( 布尔表达式 3)

then

--[ 在布尔表达式 3 为 true 时执行该语句块 --]

else

--[ 如果以上布尔表达式都不为 true 则执行该语句块 --]

end

if...else 语句

Lua if 语句允许嵌套, 这就意味着你可以在一个 if 或 else if 语句中插入其他的 if 或 else if 语句。Lua if 嵌套语句语法格式如下:

if( 布尔表达式 1)

then

--[ 布尔表达式 1 为 true 时执行该语句块 --]

if(布尔表达式 2)

then

--[ 布尔表达式 2 为 true 时执行该语句块 --]

end

end

范例:

a=1

if(a>0) then a=a+1

if(a==2) then a=a+11

end

print(a)

end

Lua 函数

在Lua中,函数是对语句和表达式进行抽象的主要方法。既可以用来处理一些特殊的工作,也可以用来计算一些值。

Lua 提供了许多的内建函数,你可以很方便的在程序中调用它们,如print()函数可以将传入的参数打印在控制台上。

Lua 函数主要有两种用途:

1.完成指定的任务,这种情况下函数作为调用语句使用;

2.计算并返回值,这种情况下函数作为赋值语句的表达式使用

function returenMaxValue(v1,v2)

if(v1>v2)

thenresult=v1

else

result=v2

return result

end

end

print(returenMaxValue(11,19))

Lua 运算符

运算符是一个特殊的符号,用于告诉解释器执行特定的数学或逻辑运算。Lua提供了以下几种运算符类型:

  • 算术运算符
  • 关系运算符
  • 逻辑运算符
  • 其他运算符

算术运算符

下表列出了 Lua 语言中的常用算术运算符,设定 A 的值为10,B 的值为 20:

操作符

描述

实例

+

加法

A + B 输出结果 30

-

减法

A - B 输出结果 -10

*

乘法

A * B 输出结果 200

/

除法

B / A w输出结果 2

%

取余

B % A 输出结果 0

^

乘幂

A^2 输出结果 100

-

负号

-A 输出结果v -10

关系运算符

下表列出了 Lua 语言中的常用关系运算符,设定 A 的值为10,B 的值为 20:

操作符

描述

实例

==

等于,检测两个值是否相等,相等返回 true,否则返回 false

(A == B) 为 false。

~=

不等于,检测两个值是否相等,相等返回 false,否则返回 true

(A ~= B) 为 true。

>

大于,如果左边的值大于右边的值,返回 true,否则返回 false

(A > B) 为 false。

<

小于,如果左边的值大于右边的值,返回 false,否则返回 true

(A < B) 为 true。

>=

大于等于,如果左边的值大于等于右边的值,返回 true,否则返回 false

(A >= B) 返回 false。

<=

小于等于, 如果左边的值小于等于右边的值,返回 true,否则返回 false

(A <= B) 返回 true。

逻辑运算符

下表列出了 Lua 语言中的常用逻辑运算符,设定 A 的值为 true,B 的值为 false:

操作符

描述

实例

and

逻辑与操作符。 若 A 为 false,则返回 A,否则返回 B。

(A and B) 为 false。

or

逻辑或操作符。 若 A 为 true,则返回 A,否则返回 B。

(A or B) 为 true。

not

逻辑非操作符。与逻辑运算结果相反,如果条件为 true,逻辑非为 false。

not(A and B) 为 true。

其他运算符

下表列出了 Lua 语言中的连接运算符与计算表或字符串长度的运算符:

操作符

描述

实例

..

连接两个字符串

a..b ,其中 a 为 "Hello " , b 为 "World", 输出结果为 "Hello World"。

#

一元运算符,返回字符串或表的长度。

#"Hello" 返回 5

Lua 字符串

字符串或串(String)是由数字、字母、下划线组成的一串字符。

Lua 语言中字符串可以使用以下三种方式来表示:

单引号间的一串字符。

双引号间的一串字符。

和[[ ]]间的一串字符。

范例:

str_1="stringtype_1"

str_2=\'stringtype_2\'

str_3=[["stringtype_3"]]

print(str_1)

print(str_2)

print(str_3)

字符串操作

result=string.upper("upper") //字符串转大写

print(result)

result=string.lower("LOWER")//字符串转小写

print(result)

result=string.reverse("reverse ")//字符串翻转

print(result)

result=string.len("len")//字符串长度

print(result)

字符串格式化

Lua 提供了 string.format() 函数来生成具有特定格式的字符串, 函数的第一个参数是格式 , 之后是对应格式中每个代号的各种数据。

字符串格式化

str_1="aaa"

str_2="bbb"

result =string.format("%s,%s",str_1,str_2)

print(result)

日期格式化:

day=1

month=5

year=2017

date=string.format("日期:%02d/%02d/%03d",day,month,year)

print(date)

Lua 数组

数组,就是相同数据类型的元素按一定顺序排列的集合,可以是一维数组和多维数组。

Lua 数组的索引键值可以使用整数表示,数组的大小不是固定的。

array={"hu","hj"}

for i=0,2 do

print(array[i])

end

--nil

-- hu

-- hj

-- 我们发现上述代码,索引为0时,从输出了nil lua数组索引默认为1.

正如你所看到的,我们可以使用整数索引来访问数组元素,如果知道的索引没有值则返回nil。

在 Lua 索引值是以 1 为起始,但你也可以指定 0 开始。

除此外我们还可以以负数为数组索引值:

array={}

for i=-10,0 do

array[i]=i*2

print(array[i])

end

多维数组

array={}

for i=1,3 do

array[i]={}

for j=1,3 do

array[i][j]=i*j

end

end

for i=1,3 do

for j=1,3 do

print(array[i][j])

end

end

-- 123

-- 246

-- 369

Lua 迭代器

泛型 for 迭代器

泛型 for 在自己内部保存迭代函数,实际上它保存三个值:迭代函数、状态常量、控制变量。

泛型 for 迭代器提供了集合的 key/value 对,语法格式如下:

for k, v in pairs(t) do

print(k, v)

end

范例代码:

table={"huhu","jack","ukraine"}

for k,v in pairs(table) do

print(k,v)

end

Lua table(表)

table 是 Lua 的一种数据结构,用来帮助我们创建不同的数据类型,如:数字、字典等。

Lua table 使用关联型数组,你可以用任意类型的值来作数组的索引,但这个值不能是 nil。

Lua table 是不固定大小的,你可以根据自己需要进行扩容。

table(表)的构造

构造器是创建和初始化表的表达式。表是Lua特有的功能强大的东西。最简单的构造函数是{},用来创建一个空表。

-- 初始化表

mytable = {}

-- 指定值

mytable[1]= "Lua" --使用数字作为键

table["strKey"]="value" --使用字符串作为键的写法1

table.strKey="value" --使用字符串作为键的写法2

-- 移除引用

mytable = nil

-- lua 垃圾回收会释放内存

范例代码-1:

table={"value1","value2"}

table["other1"]="other_value1"

table["other2"]=" other_value2"

for k,v in pairs(table) do

print(k,v)

end

--1 value1

--2 value2

--other1 other_value1

--other2 other_value2

范例代码-2:

m_table={"a","b","c"}

print("m_table类型是=",type(m_table))

temp_table=m_table

print("temp_table指向m_table,temp_table[1]=",temp_table[1])

temp_table[1]="aa" --修改m_table[1]的值

temp_table=nil

print("释放temp_table后 m_table[1]=",m_table[1])

Table连接:

m_table={"a","b","c"}

temp=table.concat(m_table) --注意table是关键字

print(temp)

插入和移除:

插入:

m_table={"a","b","c"}

table.insert(m_table,"d")

print(m_table[4])

移除:

table.remove(m_table) --移除方法,会移除最后一个元素

for k,v in pairs(m_table) do

print(k,v)

end

排序:

字母排序:

str={"a","d","b","c"}

for k,v in pairs(str) do

print("排序前:"..k..":"..v)

end

table.sort(str)

for k,v in pairs(str) do

print("排序后:"..k..":"..v)

end

数字排序:

a=1

b=2

c=3

d=4

str={a,d,b,c}

for k,v in pairs(str) do

print("排序前:"..k..":"..v)

end

table.sort(str)

for k,v in pairs(str) do

print("排序后:"..k..":"..v)

end