LUA全总结
LUA全總結
------------------------------------------------------------------------------ --2018.7.21 do --開啟或關閉printxprint = printset_print = function(yes)print = yes and xprint or function()endendset_print(false) enddo --第5章:函數--只有一個參數時: 字符串或表時,可以不寫括號--將具有多個返回值的函數f1傳入函數f2時,如作為f2最后一個參數,則f1所有返回值都會當作f2函數參數--否則,只有f1的第一個返回值被傳入f2參數x = function()return 1, 2, 3, 4endprint {1,2, 3}print "abcd"print(x()) --全部參數輸出了 : 1 2 3 4 print("begin", x()) --全部參數輸出了 : begin 1 2 3 4print(x(), " end") --輸出結果:1 end--lua是將每個程序塊(chunck)作為一個函數來處理的local fact--遞歸函數必須先聲明fact = function(n) --遞歸函數必須先聲明if n==0 then return 1 endreturn fact(n-1)*nendprint(fact(4))--變長參數local xfunc = function( ... )local a1, a2 , a3 = ...print(a1, a2, a3)endxfunc(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 doprint(names[i])endfor i, v in ipairs(names) doprint(names[i], v)end --閉包,一個閉包就是函數加上其所需訪問的“非局部變量”--閉包 = 函數 + upvalue--函數本身是一個特殊的閉包,其實LUA中沒有函數,只有閉包--只所以能實現閉包,原因是【函數是第一類型值】--即函數是一個持續存在的變量,而不是傳統的調用過程--傳統的函數調用完后函數就出棧了--第一類型值的函數可以持續存在,因此它內部局部變量及“非局部變量”也就可以持續存在function newCounter()local i = 0return function( )i = i + 1return iendendlocal c1 = newCounter() --由于i被c1引用住了,因上newCounter這個【函數變量】調用完后沒有釋放print(c1()) --1print(c1()) --2local c2 = newCounter() --一個新的閉包print(c2()) --1print(c1()) --3print(c2()) --2print(c2()) --3end do --第7章:編寫迭代器,閉包原理應用----------------------------------------------------利用for in 范圍模板實現一個自定義迭代器--1,ipair類型local old_ipairs = ipairslocal ipairs = function(t)print("---------new-ipairs------------")local i = 0return function( )i = i + 1return t[i] and i, t[i] --返回nil時,迭代結束endendlocal 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 = pairslocal pairs = function(t)print("---------new pairs------------")return next, t, nil --泛型for模板要求返回三個值:迭代器函數,數據表,控制器endlocal 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,棧層及upvaluelocal sumx = 0local add = function(a, b) ----stack layer 1local 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) doprint(k, v)end--1,upvalue是一個變量--這里的sumx就是add的一個upvaluesumx = a + b return a + bendlocal function oadd() --stack layer 2 --2,upvalue是一個函數--這里的add就是oadd的一個upvalueadd(1,2) end----stack layer 3--處在這一層時,namewhat就是main oadd() enddo --全局表,環境CSceneManager = {}for k, v in pairs(_G) doprint(k, v)endset_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 = 10newEnv.tx = 20 --等價于 tx = 20--4,【環境的私有變量】--注意:local聲明的變量不屬于環境,卻可以被環境使用,在環境外不能被訪問--因此,環境中的local變量就像是環境的私有變量,這是一個非常好的機制--模塊本身是用環境機制來實現的,因此模塊中的局部變量也相當于模塊的私有變量local lgx = 123 --不是環境中的東西--5,【環境不能改變外界環境,局部變量可以】--此函數是local,因此是暫時性的對系統的print進行了覆蓋--若不帶local,則是新環境中的一個普通函數,不是對系統函數的覆蓋local print = function(...) xprint(">>", ...)endgx = lgx + 3print(gx) --調用被覆蓋的系統printsetfenv(1, env) --手動切換,恢復原來環境--使用環境名訪問環境中產生的變量print(newEnv.gx, newEnv.tx, newEnv.lgx) --10 20 nilprint(gx, tx, lgx) --nil nil 123endfx() --函數環境在函數結束后自動恢復為原來環境,也可以在函數中切換,如上--這里有點奇怪,newEnv.print不為nilprint("after-newEnv:", newEnv.gx, newEnv.print, newEnv.lgx) enddo --元方法,元表local ta = {1, 2, 3}local tb = {4, 5, 6}local mt = {__add = function(a, b) --相當于+號運算符重載local ret = {}for i=1, #a doret[i] = a[i] + b[i] endreturn retend,__eq = function(a, b) --重載 == 運算符for i=1, #a doif a[i] ~= b[i] thenreturn falseendendmt.name = "hello"; --【錯誤】這時候mt還未定義完成,這里mt為nilreturn trueend,name = "rich",age = 30,}--設置元表相當于繼承--元表相當于基類,這里t為子類mt.__index = function(t, k)return mt[k] --這里就可以用mt了endmt.__newindex = function(t, idx, val)--注意,這里必須用rawset,而不能用t[idx] = val,這會導致遞歸調用--因為t[idx] = val仍會觸發 __nexindex調用rawset(t, idx, val)endmt.getname = function(self)return "namexxx"end--設置元表,--若子類中找不到某個變量時,就去調用基類的__index(tb, k)--注意:函數也是一個普通變量(第一類型值)setmetatable(tb, mt) --ta或tb任何一個實現了__add就可以--打印基類的所有變量,包括了函數for k, v in pairs(mt) doprint(k, v)endlocal tc = ta + tb;for k, v in pairs(tc) doprint(k, v)endprint(ta == tb)--調用步驟:若子類中沒有,則調用基類的__index方法print(tb.name)print(tb.__index(tb, "name")) --LUA的做法print(tb:getname())--rawget是在當前表中取,若不存在也不去基類中執行__index取得返回值--rawset是在當前表中對變量K設置,若K不存在也不去基類中執行__newindex--當對子類變量賦值時,若該變量不存在,LUA會去基類中找 __newindextb.gender = 'male' --直接設置到tb中,而不是元表中print("-----------", tb.gender, mt.gender)--rawget(table, index)--注意rawget的第二個參數必須是字符串表示的key,因為lua會執行 table[index]print("rawget tb.gender", rawget(tb, "gender")) endprint("-----------------------------------") do --通用問題:程序設計中用函數返回一個局部變量(對象)有什么問題 --本質上講,函數返回一個變量時,是對該變量進行了一次拷貝,將拷貝返回(匿名變量返回本身) --如果變量是基本數據類型,就沒有問題, --如果變量是指針,也沒有問題 --如果變量是個對象,對象中有【堆指針】,就有問題 --具體是:臨時對象離開函數域后被析構,析構中必須釋放指針指向的堆內存 --這樣,函數的接收者使用指針時就會崩潰,因為它指向的內存已經被釋放了,指針非法了 local func = function(t )local t1 = {a =1 , b =2 , c=3}return t1 --拷貝一個t1的副本交給接收者,也可以說接收者就是t1的直接拷貝--return {a = 1, b= 2, c = 3} --這就是匿名變量,直接將它返回給接收者,不拷貝 endlocal t2 = func(t1) t2.a = 30 print(t2.a) end -------------------------------------------------------------------------------?
posted on 2018-07-30 17:09 時空觀察者9號 閱讀(...) 評論(...) 編輯 收藏
總結
- 上一篇: C++全总结
- 下一篇: 复习笔记2018.8.3