------------------------------------------------------------------------------ --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 est1.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 -------------------------------------------------------------------------------