• Lua3


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

    1、数组

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

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

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

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

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

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

    2、二维数组

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

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

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

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

    3、链表

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

    list = nil
    for i = 1, 10 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:windowsmod
    /usr/local/lua/mod/mod.lua

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

    ;.?.lua;D:Lua5.1lua?.lua;D:Lua5.1lua?init.lua;D:Lua5.1?.lua;D:Lua5.1?init.lua;D:Lua5.1lua?.luac

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

    .?.dll;.?51.dll;D:Lua5.1?.dll;D:Lua5.1?51.dll;D:Lua5.1clibs?.dll;D:Lua5.1clibs?51.dll;D:Lua5.1loadall.dll;D:Lua5.1clibsloadall.dll

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

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

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

    require "jellythink"
    lua: test.lua:1: module 'jellythink' not found:
         no field package.preload['jellythink']
         no file '.jellythink.lua'
         no file 'D:Lua5.1luajellythink.lua'
         no file 'D:Lua5.1luajellythinkinit.lua'
         no file 'D:Lua5.1jellythink.lua'
         no file 'D:Lua5.1jellythinkinit.lua'
         no file 'D:Lua5.1luajellythink.luac'
         no file '.jellythink.dll'
         no file '.jellythink51.dll'
         no file 'D:Lua5.1jellythink.dll'
         no file 'D:Lua5.1jellythink51.dll'
         no file 'D:Lua5.1clibsjellythink.dll'
         no file 'D:Lua5.1clibsjellythink51.dll'
         no file 'D:Lua5.1loadall.dll'
         no file 'D:Lua5.1clibsloadall.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: 00375628
    table     table: 00373198
    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: 00375638
    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=199
    -- 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 = 0
    for i=1,100000 do s = s + i end
    print(string.format("elapsed time: %.2f
    ", os.clock() - x))

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

  • 相关阅读:
    编写SASS代码
    表单
    动画和变形
    图片多媒体
    基本概念
    弹性布局
    HTML和CSS概述
    页面的制作过程
    盒子定位体系
    css盒子
  • 原文地址:https://www.cnblogs.com/MrZivChu/p/lua3.html
Copyright © 2020-2023  润新知