LUA全总结

------------------------------------------------------------------------------
--2018.7.21
do --开启或关闭print
    xprint = print
    set_print = function(yes)
        print = yes and xprint or function()end
    end
    set_print(false)
end

do --第5章:函数
    --只有一个参数时: 字符串或表时,可以不写括号
    --将具有多个返回值的函数f1传入函数f2时,如作为f2最后一个参数,则f1所有返回值都会当作f2函数参数
    --否则,只有f1的第一个返回值被传入f2参数
    x = function()
        return 1, 2, 3, 4
    end
    print {1,2, 3}
    print "abcd"
    print(x()) --全部参数输出了 : 1 2 3 4 
    print("begin", x()) --全部参数输出了 : begin 1 2 3 4
    print(x(), " end") --输出结果:1 end

    --lua是将每个程序块(chunck)作为一个函数来处理的
    local fact--递归函数必须先声明
    fact = function(n) --递归函数必须先声明
        if n==0 then return 1 end
        return fact(n-1)*n
    end

    print(fact(4))


    --变长参数
    local xfunc = function( ... )
        local a1, a2 , a3 = ...
        print(a1, a2, a3)
    end
    xfunc(1, 3.2, "name")
end
do --第6章:闭包原理,upvalue,函数
    local names = {"Peter", "Paul", "Mary"}
    local grades = {Peter = 10, Paul = 7, Mary = 8}
    table.sort( names, function(n1, n2)
        return grades[n1] > grades[n2]
    end)

    for i=1, #names do
        print(names[i])
    end
    for i, v in ipairs(names) do
        print(names[i], v)
    end 

    --闭包,一个闭包就是函数加上其所需访问的“非局部变量”
    --闭包 = 函数 + upvalue
    --函数本身是一个特殊的闭包,其实LUA中没有函数,只有闭包
    --只所以能实现闭包,原因是【函数是第一类型值】
    --即函数是一个持续存在的变量,而不是传统的调用过程
    --传统的函数调用完后函数就出栈了
    --第一类型值的函数可以持续存在,因此它内部局部变量及“非局部变量”也就可以持续存在
    function newCounter()
        local i = 0
        return function( )
            i = i + 1
            return i
        end
    end

    local c1 = newCounter() --由于i被c1引用住了,因上newCounter这个【函数变量】调用完后没有释放
    print(c1()) --1
    print(c1()) --2
    local c2 = newCounter() --一个新的闭包
    print(c2()) --1
    print(c1()) --3
    print(c2()) --2
    print(c2()) --3

end
do --第7章:编写迭代器,闭包原理应用
    --------------------------------------------------
    --利用for in 范围模板实现一个自定义迭代器
    --1,ipair类型
    local old_ipairs = ipairs
    local ipairs = function(t)
        print("---------new-ipairs------------")

        local i = 0
        return function( )
            i = i + 1
            return  t[i] and i, t[i] --返回nil时,迭代结束
        end
    end

    local dat = {1, 2, 3, 10, 4, "hello"}

    --for后面的变量列表i, v是由迭代器函数的返回值决定的,个数不限
    for i, v in ipairs(dat) do --xpairs()函数只执行了一次
        print(i, v) --注意
    end

    --2,pair类型
    local old_pairs = pairs
    local pairs = function(t)
        print("---------new pairs------------")
        return next, t, nil --泛型for模板要求返回三个值:迭代器函数,数据表,控制器
    end

    local kvt = {
        a = 1,b = 2, c= 3
    }


    for k, v in pairs(kvt) do --k, v这两个变量接收的是next的返回值
        print(k, v)
    end
end
------------------------------------------------------------------------------
--2018.7.22
do --debug.getinfo,栈层及upvalue
    local sumx = 0
    local  add = function(a, b) ----stack layer 1
        local info = debug.getinfo(3, 'nuS') --stack layer 0
        --输出
        --name add                        --函数名add
        --what lua                      --是一个lua调用
        --namewhat upvalue                 --函数被调用时,是一个upvalue类型的变量
        --numps 1                         --函数本身有一个upvalue类型变量sumx
        --short_src F:\code\test1.lua

        --namewhat 用来说明函数类型,是global, local,field 还是upvalue
        --what 函数类型: lua, C, main
        --main是处于LUA文件最高层,即全局代码块,主块(main chunk)
        for k, v in pairs(info) do
            print(k, v)
        end

        --1,upvalue是一个变量
        --这里的sumx就是add的一个upvalue
        sumx = a + b 
        return a + b
    end

    local function oadd() --stack layer 2    
        --2,upvalue是一个函数
        --这里的add就是oadd的一个upvalue
        add(1,2)    
    end

    ----stack layer 3
    --处在这一层时,namewhat就是main
    oadd()
end

do --全局表,环境
    CSceneManager = {}
    for k, v in pairs(_G) do
        print(k, v)
    end

    set_print(true)
    local newEnv = {}
    local function fx( )
        --1,【函数环境】
        --开辟了一个全新的运行环境,它是一张表,后面的程序的视野被限定在了这个环境中
        --不能访问环境以外的东西【除非设置了元表】,也不可能对外界造成影响
        --环境的含义有2层:
        --1,程序在环境中运行,视野被限定在了环境内,见不到环境外的东西
        --2,程序在环境中运行,对环境产生改变,使环境产生了变量[函数也是],
        --程序运行结束后,外界可以通过环境来访问其中的变量

        --2,【环境元表,一个通往外部的通道】
        --带元表的环境就像一个:封装的环境+一个通往外界的通道
        setmetatable(newEnv, {__index = _G}) --设置环境通往外界的通道

        --3,【设置环境,函数环境】
        --设置新环境之前,记录下旧环境,以备恢复之用
        local env = getfenv()
        setfenv(1, newEnv)
        gx = 10             --等价于 newEnv.gx = 10
        newEnv.tx = 20         --等价于 tx = 20
    
        --4,【环境的私有变量】
        --注意:local声明的变量不属于环境,却可以被环境使用,在环境外不能被访问
        --因此,环境中的local变量就像是环境的私有变量,这是一个非常好的机制
        --模块本身是用环境机制来实现的,因此模块中的局部变量也相当于模块的私有变量
        local lgx = 123        --不是环境中的东西

        --5,【环境不能改变外界环境,局部变量可以】
        --此函数是local,因此是暂时性的对系统的print进行了覆盖
        --若不带local,则是新环境中的一个普通函数,不是对系统函数的覆盖
        local print = function(...) 
            xprint(">>", ...)
        end

        gx = lgx + 3
        print(gx)            --调用被覆盖的系统print
        setfenv(1, env)        --手动切换,恢复原来环境

        --使用环境名访问环境中产生的变量
        print(newEnv.gx, newEnv.tx, newEnv.lgx)     --10 20 nil
        print(gx, tx, lgx)    --nil nil 123
    end
    
    fx() --函数环境在函数结束后自动恢复为原来环境,也可以在函数中切换,如上

    --这里有点奇怪,newEnv.print不为nil
    print("after-newEnv:", newEnv.gx, newEnv.print, newEnv.lgx)
end

do --元方法,元表
    local ta = {1, 2, 3}
    local tb = {4, 5, 6}
    local mt = {
        __add = function(a, b) --相当于+号运算符重载
            local ret = {}
            for i=1, #a do
                ret[i] = a[i] + b[i]        
            end
            return ret
        end,

        __eq = function(a, b) --重载 == 运算符
            for i=1, #a do
                if a[i] ~= b[i] then
                    return false
                end
            end

            mt.name = "hello"; --【错误】这时候mt还未定义完成,这里mt为nil
            return true
        end
        ,

        name = "rich",
        age = 30,
    }

    --设置元表相当于继承
    --元表相当于基类,这里t为子类
    mt.__index = function(t, k)
        return mt[k] --这里就可以用mt了
    end
    mt.__newindex = function(t, idx, val)
        --注意,这里必须用rawset,而不能用t[idx] = val,这会导致递归调用
        --因为t[idx] = val仍会触发 __nexindex调用
        rawset(t, idx, val)
    end
    mt.getname = function(self)
        return "namexxx"
    end

    --设置元表,
    --若子类中找不到某个变量时,就去调用基类的__index(tb, k)
    --注意:函数也是一个普通变量(第一类型值)
    setmetatable(tb, mt) --ta或tb任何一个实现了__add就可以

    --打印基类的所有变量,包括了函数
    for k, v in pairs(mt) do
        print(k, v)
    end

    local tc = ta + tb;
    for k, v in pairs(tc) do
        print(k, v)
    end
    print(ta == tb)

    --调用步骤:若子类中没有,则调用基类的__index方法
    print(tb.name)
    print(tb.__index(tb, "name")) --LUA的做法
    print(tb:getname())

    --rawget是在当前表中取,若不存在也不去基类中执行__index取得返回值
    --rawset是在当前表中对变量K设置,若K不存在也不去基类中执行__newindex
    --当对子类变量赋值时,若该变量不存在,LUA会去基类中找 __newindex
    tb.gender = 'male' --直接设置到tb中,而不是元表中
    print("-----------", tb.gender, mt.gender)

    --rawget(table, index)
    --注意rawget的第二个参数必须是字符串表示的key,因为lua会执行 table[index]
    print("rawget tb.gender", rawget(tb, "gender"))
end

print("-----------------------------------")
do
--通用问题:程序设计中用函数返回一个局部变量(对象)有什么问题
--本质上讲,函数返回一个变量时,是对该变量进行了一次拷贝,将拷贝返回(匿名变量返回本身)
--如果变量是基本数据类型,就没有问题,
--如果变量是指针,也没有问题
--如果变量是个对象,对象中有【堆指针】,就有问题
--具体是:临时对象离开函数域后被析构,析构中必须释放指针指向的堆内存
--这样,函数的接收者使用指针时就会崩溃,因为它指向的内存已经被释放了,指针非法了
local func = function(t )
    local t1 = {a =1 , b =2 , c=3}
    return t1 --拷贝一个t1的副本交给接收者,也可以说接收者就是t1的直接拷贝
    --return {a = 1, b= 2, c = 3} --这就是匿名变量,直接将它返回给接收者,不拷贝
end

local t2 = func(t1)
t2.a = 30
print(t2.a)
end
-------------------------------------------------------------------------------

 

posted @ 2018-07-30 17:09  时空观察者9号  阅读(313)  评论(0编辑  收藏  举报