上一篇: Lua基础学习(二) 

Lua迭代器

泛型 for 迭代器

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

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

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

在学习 for循环的时候有学习到泛型 for。

无状态迭代器

无状态的迭代器是指不保留任何状态的迭代器,通常用两个变量(状态常量和控制变量)获取下一个元素,典型的例子就是ipairs。使用起来也非常简单,如下:

array={1,2,3,4,5,6,7}
for k,v in ipairs(array) do
  print(k,v)
end

输出如下: 

 

lua if 或 且 lua if then_lua if 或 且

实现一个ipairs也非常简单:

array={1,2,3,4,5,6,7}
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

for k,v in ipairs(array) do
  print(k,v)
end

 

lua if 或 且 lua if then_迭代器_02

调用的迭代器会一直到第一nil出现停止,也就是说如果一个数组内中间有nil,后面的就会被忽略,只能用下标来访问

复杂状态迭代器

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

array={1,2,3,4,5,6,7}
function elementIterator(collection)
  local index = 0
  local count = #collection
  --闭包函数
  return function()
    index = index + 1
	if index <= count
	then
	  --返回迭代器的当前元素
	  return collection[index]
	end
  end
end

for element in elementIterator(array) do
  print(element)
end

输出:

lua if 或 且 lua if then_迭代器_03

 尽可能的编写无状态的迭代器,如果写不了无状态的迭代器,就用基于闭包函数的迭代器。

Lua table(表)

table的构造

--table 初始化
mytable={}

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

--移除引用
mytable=nil

当我们为 table a 并设置元素,然后将 a 赋值给 b,则 a 与 b 都指向同一个内存。如果 a 设置为 nil ,则 b 同样能访问 table 的元素。如果没有指定的变量指向a,Lua的垃圾回收机制会清理相对应的内存。

示例:

a={}
a[1]="Lua"
print("数组a索引为1:",a[1])
b=a
b[1]="C#"
print("数组b索引为1:",b[1])
b=nil
print("b为nil后,数组a索引为1:",a[1])
print("b为nil后,数组b:",b)
a=nil
print("a为nil后,数组a:",a)

输出:

lua if 或 且 lua if then_lua_04

b为nil后,数组b已经是nil了,但是因为数组a的引用还没有被释放,所以数组a索引为1的时候还是有值的,但是当a为nil后,a理所应当的被Lua的垃圾回收清理掉了

table的操作

table库的一些对table的操作

table.concat

连接数组元素,可以指定连接的时候分割字符,可以指定连接的索引

示例:

colors={"red","black","orange","yellow","white"}
--连接数组每个元素
print(table.concat(colors))
--连接每个元素,用,隔开
print(table.concat(colors,","))
--连接索引2-5的元素,用,隔开
print(table.concat(colors,",",2,5))

lua if 或 且 lua if then_lua_05

table.insert 

在数组插入元素,有3个参数,中间参数可以不写,默认是最后一个元素

示例:

colors={"red","black","orange","yellow"}
--没有索引,默认在最后插入
table.insert(colors,"white")
print(table.concat(colors,','))
--有索引,在索引处插入
table.insert(colors,3,"purple")
print(table.concat(colors,','))

 输出:

lua if 或 且 lua if then_lua if 或 且_06

table.remove 

删除数组中元素,有两个参数,第二个参数可以不写,默认删除最后一个,删除中间的时候,后面的元素会前移

示例:

colors={"red","black","orange","yellow"}
--默认删除最后一个元素
table.remove(colors)
print(table.concat(colors,','))
--删除索引为2的元素
table.remove(colors,2)
print(table.concat(colors,','))

输出:

lua if 或 且 lua if then_lua if 或 且_07

table.sort 

对数组排序 ,也有两个参数,第二个参数是一个比较函数,用来执行排序方式

示例:

colors={"red","black","orange","yellow"}
--默认升序排序
table.sort(colors)
print(table.concat(colors,','))

function compare(a,b)
  return a > b
end
--加上比较函数过后,降序排序
table.sort(colors,compare)
print(table.concat(colors,','))

输出:

lua if 或 且 lua if then_Lua_08

Lua模块与包

模块类似于一个封装库,从 Lua 5.1 开始,Lua 加入了标准的模块管理机制,可以把一些公用的代码放在一个文件里,以 API 接口的形式在其他地方调用,有利于代码的重用和降低代码耦合度。

定义一个简单的模块

--保存为module.lua文件
module={}
module.constant="这是一个常量"
function module.func1()
  io.write("这是一个公有函数!\n")
end
local function func2()
  print("这是一个私有函数!")
end

function module.func3()
  func2()
end

return module

由上可知,模块的结构就是一个 table 的结构,因此可以像操作调用 table 里的元素那样来操作调用模块里的常量或函数。

require函数

require("module")
print(module.constant)
module.func3()

 输出:

lua if 或 且 lua if then_lua if 或 且_09

也可以给加载的模块或者模块函数给一个别名,比如 local m= require "module"

加载机制

对于自定义的模块,模块文件不是放在哪个文件目录都行,函数 require 有它自己的文件路径加载策略,它会尝试从 Lua 文件或 C 程序库中加载模块。

在搜索一个文件时,require采用的是一连串的模式,其中每一项都是讲模块名转换为路径名,比如路径为:

?;?.lua;C:\windows\?;/user/local/lua/?/?.lua

调用 require "sql" 就会试着打开以下文件 

sql

sql.lua

C:\windows\sql

/user/local/lua/sql/sql.lua

Lua支持层级性的模块名,用一个 . 来分隔名称中的层级。

比如上面的同样一个路径:?;?.lua;C:\windows\?;/user/local/lua/?/?.lua

如果调用 require "mod.sql" 打开的文件是:

mod/sql

mod/sql.lua

C:\windows\mod\sql

/user/local/lua/mod/sql/sql.lua

C包

loadlib可以加载和连接指定的库,这个时候并没有打开库,打开库的操作是在调用了返回的函数才打开的。然后返回初始化函数作为Lua的一个函数,这样我们就可以直接在Lua中调用他。

比如:

local path = "/usr/local/lua/lib/libluasocket.so"
-- 或者 path = "C:\\windows\\luasocket.dll",这是 Window 平台下
local f = assert(loadlib(path, "luaopen_socket"))
f()  -- 真正打开库

 

下一篇: Lua基础学习(四)