Lua语法

一、Lua语言简介

1.1 Lua语言简介

Lua 是一门由C语言编写实现的开源、简明、可扩展且高效的弱类型解释型脚本语言。由于其实现遵循C标准,它几乎能在所有的平台(windows、linux、MacOS、Android、iOS、PlayStation、XBox、wii等)上运行。

由于 Lua是 基于C构建并且完全开源,它可以方便的嵌入到各种项目中,当然也可以单独使用。Lua经常被用在很多非脚本语言的项目中,用来扩展脚本功能,提供一定的灵活性。最常见的应用场景就是各类游戏中(比如魔兽世界和愤怒的小鸟)。这篇文章将对相关内容做个入门介绍。

Lua很容易编译成静态库、动态库或以源代码的形式集成到应用程序中,并方便地与c/c++及其他语言进行互操作,因此其被称为胶水语言(glue language)。

Lua 是动态类型的,通过使用基于寄存器的解释字节码来运行虚拟机,并具有自动内存管理和垃圾收集, 使其成为配置、脚本编写、 和快速原型制作。

作为一种扩展语言,Lua没有“主”程序的概念: 它嵌入在主机客户端中工作, 称为嵌入程序或简称为主机。 宿主程序可以调用函数来执行一段 Lua 代码, 可以写入和读取Lua变量, 并且可以注册要由Lua代码调用的C函数。 通过使用 C 函数,Lua 可以增强以应对 广泛的不同领域, 从而创建共享语法框架的自定义编程语言。

1.2 Lua 开发环境

可以直接在线体验Lua: http://www.lua.org/demo.html

也可以下载对应的编译好的Lua解释器来使用: https://luabinaries.sourceforge.net/

官方推荐可以使用下面这个IDE(ZeroBrane Studio): https://studio.zerobrane.com/

二、Lua 基础语法

2.1 Lua 基础数据类型总览

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

Lua 中有 8 个基本类型分别为:nilbooleannumberstringuserdatafunctionthreadtable

数据类型 描述
nil 这个最简单,只有值 nil 属于该类,表示一个无效值(在条件表达式中相当于 false)。
boolean 包含两个值:falsetrue
number 包含整形和浮点型,默认浮点型为双精度的,可以通过自行编译解释器时 file luaconf.h 文件中的 LUA_32BITS 来设置为单精度模式
string 字符串由一对双引号或单引号来表示。可以用 2 个方括号 [[ ]] “来表示"一块"字符串。字符串连接使用的是 ..
function 由 C 或 Lua 编写的函数
userdata 表示任意存储在变量中的C数据结构
thread 表示执行的独立线路,用于执行协同程序
table Lua 中的表(table)其实是一个"关联数组”(associative arrays),用来表示普通数组、列表、符号表、集合、记录、图形、树等;数组的索引可以是数字、字符串或表类型。在 Lua 里,table 的创建是通过"构造表达式"来完成,最简单构造表达式是 { } ,用来创建一个空表。

通过 type() 方法可以获取到变量的类型,返回值是 string 类型的。

Tips: Lua认为false和nil为假,true 和非nil为真。要注意的是Lua中 0 为 true。

  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
 54
 55
 56
 57
 58
 59
 60
 61
 62
 63
 64
 65
 66
 67
 68
 69
 70
 71
 72
 73
 74
 75
 76
 77
 78
 79
 80
 81
 82
 83
 84
 85
 86
 87
 88
 89
 90
 91
 92
 93
 94
 95
 96
 97
 98
 99
100
--[[ 以下是nil类型相关测试 ]]
print(type(nil))

-- 字符串连接
print("a" .. 'b')

--[[ 以下是boolean类型相关测试 ]]

print(type(true))
print(type(false))

if nil then
    print("nil 为 true")
else
    print("nil 为 false")
end

if NaN then -- NaN用于表示未定义的运算结果,如0/0
    print("NaN 为 true")
else
    print("NaN 为 false")
end

if 0 then
    print("数字 0 为 true")
else
    print("数字 0 为 false")
end

if '' then
    print("空字符串 为 true")
else
    print("空字符串 为 false")
end


--[[ 以下是number类型相关测试 ]]

print(type(2))
print(type(2.2))
print(type(0.2))
print(type(2e+1))
print(type(0.2e-1))
print(type(7.8263692594256e-06))


--[[ 以下是string类型相关测试 ]]

str1 = "This is str1." -- 声明变量,字符串写法1
str2 = 'This is str2.' -- 声明变量,字符串写法2
str3 = [[
This is str3.
]] -- 声明变量,字符串写法3

print(str1)
print(str2)
print(str3)

print("2" + 6) -- 数字类型字符串算术运算时认为会当作数字
print("2" + "6") -- 数字类型字符串算术运算时认为会当作数字
print("2 + 6") -- 这是一个单纯的字符串
-- print("error" + 1) -- 这会报错
print("error" .. 1) -- 使用 .. 拼接字符串
print("Hello" .. " " .. "Naisu" .. "!") -- 使用 .. 拼接字符串
print(#"naisu") -- 使用 # 计算字符串长度
print(#str1) -- 使用 # 计算字符串长度


--[[ 以下是table类型相关测试 ]]
-- Lua中的table是一个关联数组(associative arrays)
-- 可以当作常见的数组使用,也可以当作键值对使用,或者也可以混合使用
-- 当作键值对使用时,键可以是除nil和NaN外的任意值,值可以是除nil外的任意值

tbl1 = {} -- 创建一个空表
tbl2 = {"apple", "pear", "orange", "grape"} -- 创建一个带初值的数组类型的表
tbl3 = { c1=1, c2=2, c3=3 } -- 创建一个带初值的键值对类型的表

for key, val in pairs(tbl2) do
    print(key .. " : " .. val) -- 遍历输出表中元素,数组形式会顺序输出
end

for key, val in pairs(tbl3) do
    print(key .. " : " .. val) -- 遍历输出表中元素,键值对形式并不一定按照顺序输出
end

print(tbl2[-1]) -- 默认索引是从1开始的,但可以手动添加负索引元素
print(tbl2[0]) -- Lua的索引并非从0开始,而是从1开始 !!!
print(tbl2[1]) 
print(tbl2[4])

tbl2[5] = 233 -- 直接添加新元素
print(#tbl2) -- 计算数组长度,如果元素中有值是nil该方式使用时需要当心
print(tbl2[5])

print(tbl3["c1"]) -- 键值对通过键名获取元素
print(tbl3.c1) -- 键值对也可以通过这种方式获取元素
tbl3["c4"] = 233
tbl3.c5 = 777
print(tbl3.c4)
print(tbl3.c5)

2.2 注释

1
2
3
4
5
6
7
8
9
-- 双横线及后面的内容是单行注释

--[[ 这是多行注释
这是多行注释 ]]

--[=[ 这也是多行注释
这也是多行注释 ]=]

-- 在ZeroBrane Studio中注释中使用 [text](url) 方式将成为一个超链接

2.3 Lua字符串(String)

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

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

  • 单引号间的一串字符。
  • 双引号间的一串字符。
  • [[ 与 ]] 间的一串字符。

与其他语言一样,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
-- 字符串全部转为大写字母。
string.upper(argument)

-- 字符串全部转为小写字母。
string.lower(argument)

-- 在字符串中替换。。
---- mainString 为要操作的字符串
---- findString 为被替换的字符
---- replaceString 要替换的字符
---- num 替换次数(可以忽略,则全部替换)
string.gsub(mainString,findString,replaceString,num)

-- 在一个指定的目标字符串中搜索指定的内容(第三个参数为索引),返回其具体位置。不存在则返回 nil。
string.find (str, substr, [init, [end]])

-- 字符串反转
string.reverse(arg)

-- 返回一个类似printf的格式化字符串
string.format(...)

-- char 将整型数字转成字符并连接
string.char(...) 

-- byte 转换字符为整数值(可以指定某个字符,默认第一个字符)
string.byte(arg[,int])

-- 计算字符串长度。
string.len(arg)

-- 返回字符串string的n个拷贝(重复n次)
string.rep(string, n)

-- 链接两个字符串
str1 .. str2

-- 返回一个迭代器函数,每一次调用这个函数,返回一个在字符串 str 找到的下一个符合 pattern 描述的子串。如果参数 pattern 描述的字符串没有找到,迭代函数返回nil。
string.gmatch(str, pattern)

-- 只寻找源字串str中的第一个配对. 参数init可选, 指定搜寻过程的起点, 默认为1。
-- 在成功配对时, 函数将返回配对表达式中的所有捕获结果; 如果没有设置捕获标记, 则返回整个配对字符串. 当没有成功的配对时, 返回nil。
string.match(str, pattern, init)

-- 截取字符串。j:截取结束位置,默认为 -1,最后一个字符。
string.sub(s, i [, j])

2.4 Lua 变量

变量在使用前,需要在代码中进行声明,即创建该变量。

Lua 变量有三种类型:全局变量局部变量表中的域

Lua 中的变量全是全局变量,那怕是语句块或是函数里,除非用 local 显式声明为局部变量(与JavaScript类似)。

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

变量的默认值均为 nil

在Lua 语言中,全局变量无须声明即可使用,使用未经初始化的全局变量不会导致错误。当使用未经初始化的全局变量时,得到的结果为 nil

当把 nil 赋值给全局变量时,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
54
55
56
57
58
59
60
61
62
63
64
65
66
67
a = "hello" .. "world"

-- Lua 可以对多个变量同时赋值,变量列表和值列表的各个元素用逗号分开,赋值语句右边的值会依次赋给左边的变量。
a, b = 10, 2*x       -->       a=10; b=2*x
-- 遇到赋值语句Lua会先计算右边所有的值然后再执行赋值操作,所以我们可以这样进行交换变量的值:
x, y = y, x                     -- swap 'x' for 'y'
a[i], a[j] = a[j], a[i]         -- swap 'a[i]' for 'a[j]'

var1 = 777 -- 全局变量

function func1()
  var2 = 233 -- 全局变量
  local var3 = "naisu" -- local修饰的是局部变量
  return var2, var3
end

func1() -- 运行函数

print(var1, var2, var3) -- var3在这里不存在,会打印为nil

a, b = 22, 33 -- 可以同时对多个变量赋值
print(a, b)

a, b = b, a -- 利用这个特性可以方便的交换两个元素
print(a, b)

a, b = func1() -- 或者接收函数的多个返回值
print(a, b)

c, d = 0 -- 需要注意的是多个变量需要分别赋值
print(c, d)

-- Lua 5.2 及其之后所有的全局变量等都是挂在 _ENV 这个表中的
-- Lua 5.2 之前是相似的表是 _G,不过新版本也做了兼容 _ENV[‘_G’]=_ENV
 
print(_ENV.var1)

function func2()
    local _ENV={print = print, abb = "robot"} -- 函数内部自己的全局环境
    print(_ENV.abb)
end

func2()

-- Lua 5.4中新增的常量定义
local var <const> = "value" -- 必须在声明时赋值,之后无法修改

--[[
算数运算符
+: 加
-: 减
*: 乘
/: 除
//: 整除
%: 取余
^: 幂乘
-: 符号
]]

--[[
位运算符
&: 按位与
|: 按位或
~: 按位异或(两个值时);按位取反(一个值时)
>>: 右移
<<: 左移
]]

对 table 的索引使用方括号 []。Lua 也提供了 . 操作(当索引为字符串类型时的一种简化写法)。

当变量个数和值的个数不一致时,Lua会一直以变量个数为基础采取以下策略:

  • 变量个数 > 值的个数:按变量个数补足nil
  • 变量个数 < 值的个数:多余的值会被忽略

2.5 流程控制

  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
 54
 55
 56
 57
 58
 59
 60
 61
 62
 63
 64
 65
 66
 67
 68
 69
 70
 71
 72
 73
 74
 75
 76
 77
 78
 79
 80
 81
 82
 83
 84
 85
 86
 87
 88
 89
 90
 91
 92
 93
 94
 95
 96
 97
 98
 99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
var1 = 10

-- Lua中 do ... end 之间是一个代码块
do
  local var1 = 666
  print(var1)
end

print(var1)

-- if
print("if:")

if 0 then
  print("Lua中数值 0 为 true")
end

if nil then
  print("nil is true" )
else
  print("nil is false" )
end

if nil then
  print("nil is true" )
elseif false then
  print("false is false")
else
  print("both nil and false is false" )
end

-- while演示
print("while:")

while var1 < 13 do 
  var1 = var1 + 1
  print(var1)
end

-- repeat 类似其他语言 do ...  while。
print("repeat:")

repeat
  var1 = var1 + 1
  print(var1) 
until var1 > 15


-- for
print("for:")

for i = 0, 2 do -- i从0到2,每次以步进1递增
  print(i)      -- 注意会打印2
end

for i = 10, 1, -3 do -- i从10到1,每次以步进-3递增
  print(i)
end

-- 数值循环:var 从 exp1 变化到 exp2,每次变化以 exp3 为步长递增 var,并执行一次 "执行体"。exp3 是可选的,如果不指定,默认为1。
for var=exp1,exp2,exp3 do  
    print(var)
end  

tbl1 = {22, 33, x=666, y=777, 888 }

print("for pairs:")
for k, v in pairs(tbl1) do -- pairs是Lua提供的一个迭代器函数,适合用来遍历键值对
  print(k, v)              -- 注意输出是乱序的
end

print("for ipairs:")
for i, v in ipairs(tbl1) do -- ipairs是Lua提供的一个迭代器函数,适合用来遍历数组
  print(i, v)
end

-- break
print("break:")

for i = 0, 5 do
  print(i)      
  if i > 1 then
    break
  end
end

-- goto
print("goto:")

for i=1, 3 do
    if i <= 2 then
        goto continue -- 调至标签
    end
    print("no goto")
    ::continue:: -- 标签两边用::
    print(i)
end

--[[
关系运算符
==: 等于
~=: 不等于
<:  小于
>:  大于
<=: 小于等于
>=: 大于等于
]]

--[[
逻辑运算符
and: 逻辑与
or:  逻辑或
not: 逻辑非
]]

2.6 Lua 函数

Lua 通过关键字 function 声明一个函数。return 语句返回结果。

函数声明格式:

1
2
3
4
optional_function_scope function function_name( argument1, argument2, argument3..., argumentn)
    function_body
    return result_params_comma_separated
end

说明:

  • optional_function_scope: 该参数是可选的,用于指定函数是全局函数还是局部函数,未设置该参数默认为全局函数,如果需要设置函数为局部函数需要使用关键字 local。
  • function_name: 指定函数名称。
  • argument1, argument2, argument3..., argumentn: 函数参数,多个参数以逗号隔开,函数也可以不带参数。
  • function_body: 函数体,函数中需要执行的代码语句块。
  • result_params_comma_separated: 函数返回值,Lua语言函数可以返回多个值,每个值以逗号隔开。

函数多值返回示例:

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
function maximum (a)
    local mi = 1             -- 最大值索引
    local m = a[mi]          -- 最大值
    for i,val in ipairs(a) do
       if val > m then
           mi = i
           m = val
       end
    end
    return m, mi
end

print(maximum({8,10,23,12,5}))

函数可变参数示例:

Tips: Lua 函数可以接受可变数目的参数,和 C 语言类似,在函数参数列表中使用三点 表示函数有可变的参数。

1
2
3
4
5
6
7
8
function add(...)  
local s = 0  
  for i, v in ipairs{...} do   --> {...} 表示一个由所有变长参数构成的数组 。inpairs没有使用括号,应该是语法编译。
    s = s + v  
  end  
  return s  
end  
print(add(3,4,5,6,7))  ---> 25
  • 通常在遍历变长参数的时候只需要使用 {…},然而变长参数可能会包含一些 nil,那么就可以用 select 函数来访问变长参数了:select('#', …) 或者 select(n, …)
    • select('#', …) 返回可变参数的长度。
    • select(n, …) 用于返回从起点 n 开始到结束位置的所有参数列表。
  • 调用 select 时,必须传入一个固定实参 selector(选择开关) 和一系列变长参数。如果 selector 为数字 n,那么 select 返回参数列表中从索引 n 开始到结束位置的所有参数列表,否则只能为字符串 #,这样 select 返回变长参数的总数。

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
function func1() -- 无参数无返回值函数
  -- 语句
end

function func2(arg1, arg2) -- 带参数无返回值函数
  -- 语句
end

function func2() -- 无参数,带多个返回值的函数
  return 22, 33
end

func3 = function() -- 匿名函数直接赋值给变量
  -- 语句
end

function func4() -- 闭包
  local i = 0
  return function()
    i = i + 1
    print(i)
  end
end

f1 = func4()
f1()
f1()

f2 = func4()
f2()
f2()  

function func5(...) -- 带可变参数的函数
  local arg={...} -- 接收可变参数为表
  for i,v in ipairs(arg) do
    print(i, v)
  end
end

func5("naisu", 233, 666)

local function func6() -- 本地函数
  -- 语句
end

2.7 Lua运算符

1、算术运算符

操作符 描述 实例(设定 A 的值为10,B 的值为 20)
+ 加法 A + B 输出结果 30
- 减法 A - B 输出结果 -10
* 乘法 A * B 输出结果 200
/ 除法 B / A 输出结果 2
% 取余 B % A 输出结果 0
^ 乘幂 A^2 输出结果 100
- 负号 -A 输出结果 -10

2、关系运算符

操作符 描述 实例(设定 A 的值为10,B 的值为 20)
== 等于,检测两个值是否相等,相等返回 true,否则返回 false (A == B) 为 false。
~= 不等于,检测两个值是否相等,不相等返回 true,否则返回 false (A ~= B) 为 true。
> 大于,如果左边的值大于右边的值,返回 true,否则返回 false (A > B) 为 false。
< 小于,如果左边的值大于右边的值,返回 false,否则返回 true (A < B) 为 true。
>= 大于等于,如果左边的值大于等于右边的值,返回 true,否则返回 false (A >= B) 返回 false。
<= 小于等于, 如果左边的值小于等于右边的值,返回 true,否则返回 false (A <= B) 返回 true。

3、逻辑运算符

操作符 描述 实例(设定 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。

3、其它运算符

操作符 描述 实例
.. 连接两个字符串 a…b ,其中 a 为 “Hello " , b 为 “World”, 输出结果为 “Hello World”。
# 一元运算符,返回字符串或表的长度。 #“Hello” 返回 5

4、运算符优先级(从高到低的顺序)

1
2
3
4
5
6
7
8
^
not    - (unary)
*      /       %
+      -
..    #
<      >      <=     >=     ~=     ==
and
or

除了 ^.. 外所有的二元运算符都是左结合的。

1
2
3
4
5
a+i < b/2+1          -->       (a+i) < ((b/2)+1)
5+x^2*8              -->       5+((x^2)*8)
a < y and y <= z     -->       (a < y) and (y <= z)
-x^2                 -->       -(x^2)
x^y^z                -->       x^(y^z)          ::::右结合的:::,注意顺序

2.8 Lua数组

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

1、一维数组

1
array = {"Lua", "Tutorial"}

Tips: 在 Lua 中索引值是以 1 为起始,但你也可以指定 0 开始。还可以以负数为数组索引值。数组的索引,不代表第几个元素,而是类似map的key。

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
array = {}

for i= -2, 2 do
   array[i] = i *2
end

for i = -2,2 do
   print(array[i])
end
--[[ 
OUTPUT:
-4
-2
0
2
4
]]

2、多维数组(就是类似于value是一个map的map。)

1
2
3
4
5
6
7
8
-- 初始化数组
array = {}
for i=1,3 do
   array[i] = {}
      for j=1,3 do
         array[i][j] = i*j
      end
end

2.9 Lua迭代器

1、泛型 for 迭代器

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

1
2
3
for k, v in pairs(t) do
    print(k, v)
end

泛型 for 的执行过程:

  • 首先,初始化,计算 in 后面表达式的值,表达式应该返回泛型 for 需要的三个值:迭代函数、状态常量、控制变量;与多值赋值一样,如果表达式返回的结果个数不足三个会自动用 nil 补足,多出部分会被忽略。
  • 第二,将状态常量和控制变量作为参数调用迭代函数(注意:对于 for 结构来说,状态常量没有用处,仅仅在初始化时获取他的值并传递给迭代函数)。
  • 第三,将迭代函数返回的值赋给变量列表。
  • 第四,如果返回的第一个值为nil循环结束,否则执行循环体。
  • 第五,回到第二步再次调用迭代函数

在Lua中我们常常使用函数来描述迭代器,每次调用该函数就返回集合的下一个元素。Lua 的迭代器包含以下两种类型:

  • 无状态的迭代器
  • 多状态的迭代器

2、无状态的迭代器

无状态的迭代器 是指不保留任何状态的迭代器,因此在循环中我们可以利用无状态迭代器避免创建闭包花费额外的代价。

每一次迭代,迭代函数都是用两个变量(状态常量和控制变量)的值作为参数被调用,一个无状态的迭代器只利用这两个值可以获取下一个元素。

这种无状态迭代器的典型的简单的例子是 ipairs,它遍历数组的每一个元素,元素的索引需要是数值。

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
--迭代函数
function square(iteratorMaxCount,currentNumber)
   if currentNumber<iteratorMaxCount
   then
      currentNumber = currentNumber+1
   return currentNumber, currentNumber*currentNumber
   end
end

for i,n in square,3,0
do
   print(i,n)
end

--OUTPUT:
1    1
2    4
3    9

迭代的状态包括被遍历的表(循环过程中不会改变的状态常量)和当前的索引下标(控制变量),ipairs 和迭代函数都很简单,我们在 Lua 中可以这样实现:

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
--迭代函数。参数a:是状态常量,i:控制变量
function iter (a, i)
    i = i + 1
    local v = a[i]
    if v then
       return i, v
    end
end
 
function ipairs (a)
    return iter, a, 0
end

当 Lua 调用 ipairs(a) 开始循环时,他获取三个值:迭代函数 iter状态常量 a控制变量初始值 0;然后 Lua 调用 iter(a,0) 返回 1, a[1](除非 a[1]=nil);第二次迭代调用 iter(a,1) 返回 2, a[2]……直到第一个 nil 元素。

3、多状态的迭代器

迭代器需要保存多个状态信息而不是简单的状态常量和控制变量,最简单的方法是使用闭包,还有一种方法就是将所有的状态信息封装到 table 内,将 table 作为迭代器的状态常量,因为这种情况下可以将所有的信息存放在 table 内,所以迭代函数通常不需要第二个参数。

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
array = {"Google", "Runoob"}

function elementIterator (collection)
   local index = 0
   local count = #collection   --collectioin 长度
   -- 闭包函数
   return function ()
      index = index + 1
      if index <= count
      then
         --  返回迭代器的当前元素
         return collection[index]
      end
   end
end

for element in elementIterator(array)  -- elementIterator(array) 调用的返回值(闭包) ,作为一个迭代函数。
do
   print(element)
end
--OUTPUT:
Google
Runoob

2.10 Lua table(表)

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

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

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

Lua也是通过table来解决模块(module)、包(package)和对象(Object)的。 例如string.format表示使用"format"来索引table string。

table(表)的构造

1
2
3
4
5
6
7
8
9
-- 初始化表
mytable = {}

-- 指定值
mytable[1]= "Lua"

-- 移除引用
mytable = nil
-- lua 垃圾回收会释放内存

Table 的操作:

方法 用途
table.concat (table [, sep [, start [, end]]]): concat是concatenate(连锁, 连接)的缩写. table.concat()函数列出参数中指定table的数组部分从start位置到end位置的所有元素, 元素间以指定的分隔符(sep)隔开。
table.insert (table, [pos,] value): 在table的数组部分指定位置(pos)插入值为value的一个元素. pos参数可选, 默认为数组部分末尾.
table.maxn (table) 指定table中所有正数key值中最大的key值. 如果不存在key值为正数的元素, 则返回0。(Lua5.2之后该方法已经不存在了,本文使用了自定义函数实现)
table.remove (table [, pos]) 返回table数组部分位于pos位置的元素. 其后的元素会被前移. pos参数可选, 默认为table长度, 即从最后一个元素删起。
table.sort (table [, comp]) 对给定的table进行升序排序。
Licensed under CC BY-NC-SA 4.0