Lua中的table不是一种简单的数据结构,它可以作为其它数据结构的基础。如数组、记录、线性表、队列和集合等,在Lua中都可以通过table来表示。

1、数组

使用整数来索引table即可在Lua中实现数组。因此,Lua中的数组没有固定的大小,如:

a = {}
for i = , do
a[i] =
end
print("The length of array 'a' is " .. #a)
--The length of array 'a' is 1000

在Lua中,可以让任何数作为数组的起始索引,但通常而言,都会使用1作为其起始索引值。

而且很多Lua的内置功能和函数都依赖这一特征,因此在没有充分理由的前提下,尽量保证这一规则。

下面的方法是通过table的构造器来创建并初始化一个数组的,如:

squares = {, , }

function  wyq( ... )
for i=,select('#',...) do
local temp = select(i,...)
if(type(temp)=="string") then
print("这是字符串 = "..temp)
elseif(type(temp)=="table") then
for j=,table.maxn(temp) do
print(temp[j])
end
else
print("这是数字 = "..temp)
end
end
end wyq(squares,,"hello")
--输出结果
--
--
--
--这是数字 = 2
--这是字符串 = hello

2、二维数组

在Lua中我们可以通过两种方式来利用table构造多维数组。其中,第一种方式通过“数组的数组”的方式来实现多维数组的,即在一维数组上的每个元素也同样为table对象,如:

mt = {}
function eeeee( ... )
local N =select(,...)
local M =select(,...)
for i = , N do
mt[i] = {}
for j = , M do
mt[i][j] = i * j
end
end
end eeeee(,) for i=,table.maxn(mt) do
local len = table.maxn(mt[i])
for j=,len do
print(mt[i][j])
end
end

第二种方式是将二维数组的索引展开,并以固定的常量作为第二维度的步长,如:

mt = {}
for i = , N do
for j = , M do
mt[(i - ) * M + j] = i * j
end
end

3、链表

由于table是动态的实体,所以在Lua中实现链表是很方便的。其中,每个结点均以table来表示,一个“链接”只是结点中的一个字段,该字段包含对其它table的引用,如:

list = nil
for i = , do
list = { next = list, value = i}
end local l = list
while l do
print(l.value)
l = l.next
end
--10 9 8 7 6 5 4 3 2 1

package.path 、 require 、 package.loaded

require到底是如何加载模块的呢?

用require函数只能加载一次,因为它的特性是:    1、require函数会搜索目录加载文件     2、require会判断是否文件已经加载避免重复加载同一文件。

lua文件就相当于c#中的类一样,而require就相当于c#中的using一样

首先,要加载一个模块,就必须的知道这个模块在哪里。知道了这个模块在哪里以后,才能进行正确的加载。当我们写下require “mod”这样的代码以后,Lua是如何找这个mod的呢?

这里就详细的说一说。 在搜索一个文件时,在windows上,很多都是根据windows的环境变量path来搜索,而require所使用的路径与传统的路径不同,require采用的路径是一连串的模式,

其中每项都是一种将模块名转换为文件名的方式。require会用模块名来替换每个“?”,然后根据替换的结果来检查是否存在这样一个文件,如果不存在,就会尝试下一项

。路径中的每一项都是以分号隔开,比如路径为以下字符串:

?;?.lua;c:\windows\?;/usr/local/lua/?/?.lua

那么,当我们require “mod”时,就会尝试着打开以下文件:

mod
mod.lua
c:\windows\mod
/usr/local/lua/mod/mod.lua

可以看到,require函数只处理了分号和问号,其它的都是由路径自己定义的。在实际编程中,require用于搜索的Lua文件的路径存放在变量package.path中,在我的电脑上,print(package.path)会输出以下内容:

;.\?.lua;D:\Lua\5.1\lua\?.lua;D:\Lua\5.1\lua\?\init.lua;D:\Lua\5.1\?.lua;D:\Lua\5.1\?\init.lua;D:\Lua\5.1\lua\?.luac

如果require无法找到与模块名相符的Lua文件,那Lua就会开始找C程序库;这个的搜索地址为package.cpath对应的地址,在我的电脑上,print(package.cpath)会输出以下值:

.\?.dll;.\?.dll;D:\Lua\5.1\?.dll;D:\Lua\5.1\?.dll;D:\Lua\5.1\clibs\?.dll;D:\Lua\5.1\clibs\?.dll;D:\Lua\5.1\loadall.dll;D:\Lua\5.1\clibs\loadall.dll

当找到了这个文件以后,如果这个文件是一个Lua文件,它就通过loadfile来加载该文件;如果找到的是一个C程序库,就通过loadlib来加载。

loadfile和loadlib都只是加载了代码,并没有运行它们,为了运行代码,require会以模块名作为参数来调用这些代码。如果lua文件和C程序库都找不到,怎么办?

我们试一下,随便require一个东西,比如:

require "jellythink"
lua: test.lua:: module 'jellythink' not found:
no field package.preload['jellythink']
no file '.\jellythink.lua'
no file 'D:\Lua\5.1\lua\jellythink.lua'
no file 'D:\Lua\5.1\lua\jellythink\init.lua'
no file 'D:\Lua\5.1\jellythink.lua'
no file 'D:\Lua\5.1\jellythink\init.lua'
no file 'D:\Lua\5.1\lua\jellythink.luac'
no file '.\jellythink.dll'
no file '.\jellythink51.dll'
no file 'D:\Lua\5.1\jellythink.dll'
no file 'D:\Lua\5.1\jellythink51.dll'
no file 'D:\Lua\5.1\clibs\jellythink.dll'
no file 'D:\Lua\5.1\clibs\jellythink51.dll'
no file 'D:\Lua\5.1\loadall.dll'
no file 'D:\Lua\5.1\clibs\loadall.dll'

是的,会报错的。以上就是require的一般工作流程。

自己如何定义require相关lua文件的搜索路径?(package.path

package.path用于指定require搜索的路径。

 package.path = "G:/TestLua/Assets/StreamingAssets/?.lua" --这样就会去G:/TestLua/Assets/StreamingAssets/下搜索lua文件

package.loaded

当我们有一些特殊的需求的时候,就可能会需要反复加载某个lua文件,例如我的文件lua文件动态地改变了,我要立即,或者一些其他特殊原因.

看下例子就知道了:

编写两个lua文件,a.lua和b.lua,代码分别如下

-- a.lua
myname='tom' -- b.lua
require "a"
function MyFunc()
print('my name is '..myname)
end

客户端c#代码为:

private LuaState lua;
private LuaFunction zwhFunc;
void Start()
{
lua = new LuaState();
} public void CallMethod()
{
lua.DoFileFromAge(this, "Demo.lua", delegate(System.Object[] obj) --必须重新加载Demo.lua文件,不然package.loaded是没用的,加载的永远是第一次获取的那一份,DoFileFromAge方法就是重新读取了Demo.lua文件
{
zwhFunc = lua.GetFunction("MyFunc");
zwhFunc.Call();
});
}

场景里面的一个按钮的OnCLick绑定CallMethod方法,点击一次按钮,会输出“my name is tom”,程序一直运行着,不要退!

此时我们去修改一下a.lua文件下的myname值为jerry,然后再点击一下按钮,还是会输出“my name is tom”,可以看出我们虽然修改了myname的值,但是根本没有应用过去,

这也就是require的特性所致吧(require会判断是否文件已经加载避免重复加载同一文件),如果想myname改变的值能够在程序运行的时候立马应用,这就用到了package.loaded

我们修改下b.lua,加个package.loaded["a"]  = nil 即可!我觉得这个特性还是在游戏开发的时候用到最好,避免每次修改代码,都需要重新退出再进游戏了,游戏发布之后就可以关了

-- b.lua
package.loaded["a"] = nil
require "a"
function MyFunc()
print('my name is '..myname)
end

此时你修改myname的值,变会立马应用,看到值的变化了!

至于为什么,我们来看下require函数的伪代码就知道了:

-- require和package.loaded的关系
如果没有载入任何Chunk,典型的package.loaded是类似如下的一张表
string table: 00375D48
package table: 00373C30
_G table: 00371FD8
os table:
table table:
math table: 003763C8
coroutine table: 003738A8
debug table: 00376FA0
io table: 00374DC8 -- 当我们require("main")成功后,该表会变回
string table: 00375D58
package table: 00373C38
_G table: 00371FC0
os table:
table table: 003731A0
math table: 003763D8
coroutine table: 003738B0
debug table: 00376FB0
io table: 00374DD8
main true -- 新增表项package.loaded["main"] = true
function require(virname) do
if not package.loaded[virname] then --如果package.loaded[virname]存在的话,就直接返回
return
end
local anyfileloaded = false
patternpath = (replace '?' in package.path to virname)
foreach path in patternpath split by ';' do -- virname如果含有'.', 那么'.'会被替换为'\\'
if ((chunk = loadfile(path)) ~= nil) then
chunk()
package.loaded[virname] = true -- 可以手工设置package.loaded[virname] = false来重复载入该文件
anyfileloaded = true
break
end
end if not anyfileloaded then
print error message
end
end

require是每个页面都需要吗? 

-- 入口方法Start    main.lua

require 'tempage'
require 'tempname‘ function Start()
print('my name is '..myname)
end
-- tempage.lua
myage=
-- tempname.lua
myname='tom'
print('my age is '..myage) --这句话顺利执行,我一直以为需要require myage所在的lua文件,原来不需要,如果tempage.lua加载前的相关lua文件require进了myage所在的lua文件,那么就不需要在require了!这里main.lua先require过了tempage.lua了,所以这里能访问到myage变量! --打印结果
--my age is 199
--my name is tom

collectgarbage

luanet

 

测量lua脚本执行的时间

local x = os.clock()
local s =
for i=, do s = s + i end
print(string.format("elapsed time: %.2f\n", os.clock() - x))

http://blog.sina.com.cn/s/blog_3d2d5d790100idjv.html

最新文章

  1. Spring Boot + Bootstrap 出现"Failed to decode downloaded font"和"OTS parsing error: Failed to convert WOFF 2.0 font to SFNT"
  2. window.parent与window.openner区别介绍
  3. 前端AJAX传递数组给Springmvc接收处理
  4. sqldatasource控件设置where语句
  5. your project contains error(s),please fix them before running your application.错误总结
  6. 01_Java解析XML
  7. JDK1.5新特性(四)……Autoboxing/Unboxing
  8. .NET开发不可错过的25款高效工具
  9. CreateForm(
  10. Python多层目录模块调用
  11. Mybatis #{ } 和 ${ } 区别
  12. Linux文本处理命令 -- awk
  13. 如何改变XCode的默认设置
  14. 了解Scala 宏
  15. jQuery 选择器demo练习
  16. 怎样在winform中上传图片
  17. 验证远程主机SSH指纹
  18. rap2与postman自动化测试
  19. 【Graphlab】
  20. 大专生自学html5到找到工作的心得

热门文章

  1. Uva 11997 多路归并
  2. 百度Ueditor 图片上传无反应,显示上传0张,不能点确定
  3. 2017.9.18 include指令和include动作有什么区别?
  4. 在Visual Studio 2010里面使用.NET 4.5里面新增加的HttpClient
  5. Oracle 11g基础
  6. 08_1_IO
  7. dicom和dicomdir
  8. PHP中json_encode后,在json字符串中依然显示中文的解决方案
  9. python--随笔一
  10. php 多维数组相同键值处理合并