Lua学习之function
第五章 Lua学习笔记之函数 ? 函数有两个用途 1.??????完成指定功能,函数作为调用语句使用 2.??????计算并返回值,函数作为赋值语句的表达式使用 function unpack(t,i) ? i = i or 1 ? if t[i] then ? ?????????? return t[i],unpack(t,i + 1) end ? end ? ? Lua 中的函数和 Javascript 中的有些相似,函数在书写的时候,前面都需要加上?function?这个关键字,?上篇文章中提过?function?这个关键字,他在 Lua 中也是一种类型。下面我们来看看 Lua 中的一个简单函数是怎么写的。 ?
? ??在上面的一段函数中,函数的开头需要function?关键字来修饰它,表明它是一个“函数类型” ,当然既然成为“类型” 我们在程序中也可以这样写: ?
? ??所以说,Lua 的函数是很灵活的。 ? ? 在C/C++中我们总是用"{ }" 来括起一个函数,但是Lua中有所不同,大家也注意到了上边的代码,最后跟随着一个 "end" ,这个 end 就是来表明一个函数的结尾的。好了对于Lua中函数的初步认识就到这里,更深入的我们要留在以后实践中来体会。 ? ? lua函数接受可变参数,lua讲函数的参数放在一个叫arg的表中,除了参数之外,表中还有一个域n表示参数个数 ? function g(a,b,…)end ? g(3)? a = 3,b = nil,arg = {n = 0} g(3,4) a = 3,b = 4,arg = {n=0} g(3,4,5,6) a = 3,arg = {5,6,n = 2} ? 如果只想要string.find返回的第二个值: 一个典型的方法是使用虚变量(下划线) s = "12345678" ? p = "3456" ? local _,x = string.find(s,p) ? print(x) ? 命名参数 Lua的函数参数和位置相互关联,调用时实参安顺序依次传给形参。 有时候用名字指定参数是很有用的。 比如用rename函数给一个文件重新命名,有时候我们记不得命名前后两个参数的顺序了 Function rename(arg) Return os.rename(arg.old,arg.new) end ?Rename{old = “temp.lua”,new=”temp1.lua”} 当函数参数很多时,这样处理就比较方便,简单。例如窗口创建函数; w = Window { ? x = 0,y = 0,width = 300,height = 200, title? = "lua",background = "blue", border = true ? } ? function Window(options) ? if type(options.title) ~= "string" then ? error("no title") ? elseif type(options.width) ~= "number" then ? error("no width") ? elseif type(options.height) ~= "number" then ? error("no height") ? end ? ? _Window(options.title, ? options.x or 0, options.y or 0, options.width,options.height, options.background or "white", options.border ? ) ? End ? 第六章再论函数 ? Lua中的函数有以下两个特点: 1.??????lua中的函数和其他变量(string,number) 一样,可以赋值,可以放在变量中,可以放在表中。可以作为函数参数,可以作为函数返回值。 2.??????被嵌套的内部函数可以访问他外面的数据成员 3.??????Lua函数可以是匿名的,当我们提到函数名(比如print),其实是print这个变量指向打印输出这个函数,当然,打印输出函数也可以由其他变量指向。例如: ? a = { p = print} ? a.p("hello world") ? print = math.sin ? a.p(print(1)) ? sin = a.p ? sin(10,20) ? 没错,函数就是变量,就是值。 function foo(x) ???? ???? return 2*x ? end ? foo = function (x) ? ?? return 2*x end ? 函数定义就是把function这个值赋值给foo这个变量。 我们使用function(x)…end 创建函数和 {}创建表是一个道理。 ? Table标准库有一个排序函数,接受一个表作为参数对标中的元素进行排序。 这个函数必须对不同类型的元素进行升降排序,Lua不是尽可能多的传入参数解决这种问题,而是接受一个排序函数作为参数,(类似c++的函数指针)排序函数作为输入参数,并且返回两个参数比较后的大小关系(用c++可以实现这个万能的排序算法) 例如: name = { "peter","paul","mary"} ? grades = { mary = 10,paul = 7,peter = 13 } ? table.sort(name,function (n1,n2) return grades[n1] > grades[n2] end ) ? ? 在lua中,其他函数作为函数的参数,成这个函数为高级函数,没有什么特殊的地方。 function sortbygrade (name,grades) ? ???? table.sort(name,n2) return grades[n1] > grades[n2] end) ? end ? 闭包 ? 包含在sortbygrade中的sort的参数匿名function 可以访问sortbygrade的grades在匿名function 内部grades既不是全局变量,也不是局部变量。他别称为外部的局部变量或upvalue ? function newCounter() ? ???? local i = 0 ? ???? return function () ? ?????????????? i = i + 1 ? ?????????????? return i ? ???? end ? end ? ? ? ca = newCounter() ? cb = newCounter() ? print(ca()) ? print(ca()) ? print(cb()) ? 匿名函数使用upvalue i保存他的计数 当我们调用匿名函数的时候I已经超出了他的适用范围,因为创建i的函数newCounter已经返回了。简单滴说闭包是一个函数加上他可以正确访问的upvalues,如果我们再次调用newCOunter,将创建一个新的局部变量i 因此我们得到了一个作用在新建的i上的新闭包。 技术上讲,闭包是值而不是函数。函数仅仅是闭包的一个原形声明;我们继续使用术语函数代替闭包。 ? 闭包的功能: 作为高级函数的参数。 作为函数嵌套的函数。 作为回调函数。 创建沙箱。 ? ? ? do ? ???? local oldOpen = io.open ? ???? io.open = function (filename,mode) ? ?????????????? if access_OK(filename,mode) then ? ??????????????????????? return oldOpen(filename.mode) ? ?????????????? else ? ??????????????????????? return nil,"access denied" ? ?????????????? end ? ???? end ? end ? ? ? ? ? ? ? ? ? ? ? ? ? ? 非全局函数 Lua中函数分为全局和非全局 ? 大部分作为table的域(math.sin io.read) ? 例如: ? --1.表和函数在一起 ? Lib = {} ? Lib.foo = function (x,y) return x + y end ? Lib.goo = function (x,y) return x - y end ? --2.使用表构造函数 ? Lib = { ? foo = function (x,y) return x + y end, ? goo = function (x,y) return x - y end ? } ? --3.Lua提供另一种语法方式 ? Lib = {} ? function Lib.foo (x,y) ? ? ???? return x + y ? end ? function Lib.go0 (x,y) ? ???? return x - y ? end ? ? 当我们把函数赋值给局部变量时,函数成了局部的,就是说局部函数像局部变量一样在一定范围内有效。声明局部函数的方式: Local f = function(…) … End ? Local function f (…) …. end ? 需要注意声明递归局部函数 Local face—声明和定义必须分开 ?face = function(n) ? ?? If(n==1) ??????????? Return 1 Else ??????????? Return n*face(n-1) End End ? ? 尾调用: 如果函数最后一句执行的是函数调用,我们称这种调用为尾调用 ? Function f(x) ??????????? Return g(x) ? End --g(x)即为尾调用 ? 例子中f调用g之后不会做任何事情 这时候,g不需要返回到f,所以尾调用之后,栈不保存f的任何信息。 ? 由于尾调用不需要栈空间,所以尾调用递归可以无限次进行 ? Function foo(n) ? If(n>0)then Return foo(n-1) End ? End ? 需要注意:为调用之后确实不做什么事,不做什么事的调用不一定是尾巴调用 例如: ? Function f(x) ? G(x) ? R return end --不是尾调用 ? ? 下面的例子也不是尾调用 Return g(x)+1 ? Return(g(x)) ? Return x or g(x) ? 以上表达式的最后一步计算的不是g(x)本身,所以不是尾函数 ? ? ? ?
local function languageTest() -- table test local names = {"Peter","Paul","Mary"} local grades = {Mary=10,Paul=7,Peter=8} table.sort(names,function(n1,n2) return grades[n1] > grades[n2] end) for i=1,#names do print(names[i]) end -- function test local function newCounter(name) local i = 0 return function() i = i+1 return name .. ":" .. i end end local c1 = newCounter("c1") local c2 = newCounter("c2") print(c1()) print(c1()) print(c2()) print(c1()) print(c2()) -- for test local function values(t) local i = 0; return function() i=i+1; return t[i] end end for elm in values(names) do print(elm) end -- -- for test2 -- for k in pairs(names) do -- print(k) -- end end local function tableTest() local Set = {} local mt = {} -- create a new set with teh values of the given list Set.new = function(l) local set = {} setmetatable(set,mt) for _,v in ipairs(l) do set[v] = true end return set; end Set.union = function(a,b) if getmetatable(a) ~= mt or getmetatable(b) ~= mt then error("attempt to 'add' a set with a non-set value",2); end local res = Set.new {} for k in pairs(a) do res[k] = true end for k in pairs(b) do res[k] = true end return res end Set.intersection = function(a,b) local res = Set.new {} for k in pairs(a) do res[k] = b[k] end return res end Set.tostring = function(set) local l = {} for e in pairs(set) do l[#l+1] = e end return "{" .. table.concat(l,",") .. "}" end Set.print = function(s) print(Set.tostring(s)) end mt.__add = Set.union mt.__mul = Set.intersection mt.__tostring = Set.tostring mt.__le = function(a,b) for k in pairs(a) do if not b[k] then return false end end return true end mt.__lt = function(a,b) return a<=b and not (b<=a) end mt.__eq = function(a,b) return a<=b and b<=a end local s1 = Set.new {10,20,30,50} local s2 = Set.new {30,1} local s3 = s1+s2+s2 -- local s3 = s1+s2+s2 + 8 Set.print(s3) Set.print((s1+s2)*s1) s1 = Set.new{2,4} s2 = Set.new{4,10,2} print(s1<=s2) print(s1<s2) print(s1>=s2) print(s1>s2) print(s1==s2*s1) s1 = Set.new {10,5} print(s1) -- mt.__metatable = "not your business" -- print(getmetatable(s1)) -- setmetatable(s1,{}) local Window = {} -- create a namespace --create teh prototype with default values. Window.prototype = {x=0,y=0,width=100,height=100} Window.mt = {} -- create a metatable --declare the constructor function function Window.new(o) setmetatable(o,Window.mt) return o end Window.mt.__index = function(table,key) return Window.prototype[key] end -- Window.mt.__index = Window.prototype w = Window.new {x=10,y=20} print(w.x) -- Tables with default values local function setDefault(t,d) local mt = {__index = function() return d end} setmetatable(t,mt) end local tab = {x=10,y=20} print(tab.x,tab.z) setDefault(tab,0) print(tab.x,tab.z) local mt = {__index = function(t) return t.___ end } local function setDefault(t,d) t.___ = d setmetatable(t,mt) end -- Tracking table accesses local t = {} -- original table (created somewhere) -- keep a private access to the original table local _t = t -- create proxy t = {} -- create metatable local mt = { __index = function(t,k) print("*access to element " .. tostring(k)) return _t[k] end,__newindex = function(t,k,v) print("*update of element " .. tostring(k) .. " to " .. tostring(v)) _t[k] = v -- update original table end } setmetatable(t,mt) t[2] = "hello" print(t[2]) -- Read-only tables function readOnly(t) local proxy = {} local mt = { __index = t,v) error("attempt to update a read-only table",2) end } setmetatable(proxy,mt) return proxy end days = readOnly {"Sunday","Monday","Tuesday","Wednesday","Thursday","Friday","Saturday"} print(days[1]) -- days[2] = "Noday" end local function objectTest() local Account = { balance = 0,new = function(self,o) o = o or {} -- create table is user does not provide one setmetatable(o,self) self.__index = self return o end,withdraw = function(self,v) if v>self.balance then error"insufficient funds" end self.balance = self.balance - v end,deposit = function(self,v) self.balance = self.balance + v end } local a = Account:new {balance = 0} a:deposit(100.00) print(a.balance) local b = Account:new() print(b.balance) b.balance = 123 print(b.balance) b:withdraw(100) print(b.balance) print(a.balance) -- inheritance local SpecialAccount = Account:new({ withdraw = function(self,v) if v - self.balance >= self:getLimit() then error"insufficient funds" end self.balance = self.balance - v end,getLimit = function(self) return self.limit or 0 end }) local s = SpecialAccount:new {limit=1000.00} s:deposit(100.00) s:withdraw(200.00) print("s:",s.balance) end local function main() languageTest(); tableTest(); objectTest(); end main() (编辑:李大同) 【声明】本站内容均来自网络,其相关言论仅代表作者个人观点,不代表本站立场。若无意侵犯到您的权利,请及时与联系站长删除相关内容! |