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 中的一个简单函数是怎么写的。

 

 
  
  1. function printHello(a,b)  --a,b为参数 
  2. print(a,b); 
  3. print("Hello"
  4. end 

    在上面的一段函数中,函数的开头需要function 关键字来修饰它,表明它是一个“函数类型” ,当然既然成为“类型” 我们在程序中也可以这样写:

 

 
  
  1. testFuction=function (a,b) return a+b end  
  2. --testFuction就相当于这个函数的函数名了 

    所以说,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,b = 4,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,function (n1,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)本身,所以不是尾函数

 

 

 

 

[sql] view plain copy print ?
  1. local function languageTest()   
  2.     -- table test   
  3.     local names = {"Peter""Paul""Mary"}  
  4.     local grades = {Mary=10, Paul=7, Peter=8}  
  5.     table.sort(names, function(n1, n2)   
  6.         return grades[n1] > grades[n2]  
  7.     end)  
  8.     for i=1, #names do  
  9.         print(names[i])  
  10.     end  
  11.       
  12.     -- function test   
  13.     local function newCounter(name)  
  14.         local i = 0  
  15.         return function()  
  16.                 i = i+1  
  17.                 return name .. ":" .. i  
  18.             end  
  19.     end  
  20.       
  21.     local c1 = newCounter("c1")  
  22.     local c2 = newCounter("c2")  
  23.       
  24.     print(c1())  
  25.     print(c1())  
  26.     print(c2())  
  27.     print(c1())  
  28.     print(c2())  
  29.       
  30.     -- for test   
  31.     local function values(t)  
  32.         local i = 0;  
  33.         return function() i=i+1; return t[i] end  
  34.     end  
  35.     for elm in values(names) do  
  36.         print(elm)  
  37.     end  
  38.       
  39. --  -- for test2   
  40. --  for k in pairs(names) do   
  41. --      print(k)   
  42. --  end   
  43. end  
  44.   
  45. local function tableTest()   
  46.     local Set = {}  
  47.     local mt = {}  
  48.       
  49.     -- create a new set with teh values of the given list   
  50.     Set.new = function(l)  
  51.         local set = {}  
  52.         setmetatable(set, mt)  
  53.         for _, v in ipairs(l) do set[v] = true end  
  54.         return set;  
  55.     end  
  56.       
  57.     Set.union = function(a, b)  
  58.         if getmetatable(a) ~= mt or getmetatable(b) ~= mt then  
  59.             error("attempt to 'add' a set with a non-set value", 2);  
  60.         end  
  61.         local res = Set.new {}  
  62.         for k in pairs(a) do res[k] = true end  
  63.         for k in pairs(b) do res[k] = true end  
  64.         return res  
  65.     end  
  66.       
  67.     Set.intersection = function(a, b)  
  68.         local res = Set.new {}  
  69.         for k in pairs(a) do   
  70.             res[k] = b[k]  
  71.         end  
  72.         return res  
  73.     end  
  74.       
  75.     Set.tostring = function(set)  
  76.         local l = {}  
  77.         for e in pairs(set) do   
  78.             l[#l+1] = e  
  79.         end  
  80.         return "{" .. table.concat(l, ", ") .. "}"  
  81.     end  
  82.       
  83.     Set.print = function(s)  
  84.         print(Set.tostring(s))  
  85.     end  
  86.       
  87.     mt.__add = Set.union  
  88.     mt.__mul = Set.intersection  
  89.     mt.__tostring = Set.tostring  
  90.     mt.__le = function(a, b)  
  91.         for k in pairs(a) do   
  92.             if not b[k] then return false end  
  93.         end  
  94.         return true  
  95.     end  
  96.     mt.__lt = function(a, b)  
  97.         return a<=b and not (b<=a)  
  98.     end  
  99.     mt.__eq = function(a, b)  
  100.         return a<=b and b<=a  
  101.     end  
  102.       
  103.       
  104.     local s1 = Set.new {10, 20, 30, 50}  
  105.     local s2 = Set.new {30, 1}  
  106.     local s3 = s1+s2+s2  
  107. --  local s3 = s1+s2+s2 + 8   
  108.     Set.print(s3)  
  109.     Set.print((s1+s2)*s1)  
  110.       
  111.     s1 = Set.new{2, 4}  
  112.     s2 = Set.new{4, 10, 2}  
  113.     print(s1<=s2)  
  114.     print(s1
  115.     print(s1>=s2)  
  116.     print(s1>s2)  
  117.     print(s1==s2*s1)  
  118.       
  119.     s1 = Set.new {10, 4, 5}  
  120.     print(s1)  
  121.       
  122. --  mt.__metatable = "not your business"   
  123. --  print(getmetatable(s1))   
  124. --  setmetatable(s1, {})   
  125.       
  126.     local Window = {} -- create a namespace   
  127.     --create teh prototype with default values.   
  128.     Window.prototype = {x=0, y=0, width=100, height=100}  
  129.     Window.mt = {} -- create a metatable   
  130.     --declare the constructor function   
  131.     function Window.new(o)  
  132.         setmetatable(o, Window.mt)  
  133.         return o  
  134.     end  
  135.     Window.mt.__index = function(tablekey)  
  136.         return Window.prototype[key]  
  137.     end  
  138. --  Window.mt.__index = Window.prototype   
  139.     w = Window.new {x=10, y=20}  
  140.     print(w.x)  
  141.       
  142.       
  143.     -- Tables with default values   
  144.     local function setDefault(t, d)  
  145.         local mt = {__index = function() return d end}  
  146.         setmetatable(t, mt)  
  147.     end  
  148.     local tab = {x=10, y=20}  
  149.     print(tab.x, tab.z)  
  150.     setDefault(tab, 0)  
  151.     print(tab.x, tab.z)  
  152.       
  153.     local mt = {__index = function(t) return t.___ end }  
  154.     local function setDefault(t, d)  
  155.         t.___ = d  
  156.         setmetatable(t, mt)  
  157.     end  
  158.       
  159.     -- Tracking table accesses   
  160.     local t = {} -- original table (created somewhere)   
  161.     -- keep a private access to the original table   
  162.     local _t = t  
  163.     -- create proxy   
  164.     t = {}  
  165.     -- create metatable   
  166.     local mt = {  
  167.         __index = function(t, k)  
  168.             print("*access to element " .. tostring(k))  
  169.             return _t[k]  
  170.         end,  
  171.           
  172.         __newindex = function(t, k, v)  
  173.             print("*update of element " .. tostring(k) .. " to " .. tostring(v))  
  174.             _t[k] = v -- update original table   
  175.         end  
  176.     }  
  177.     setmetatable(t, mt)  
  178.     t[2] = "hello"  
  179.     print(t[2])  
  180.       
  181.     -- Read-only tables   
  182.     function readOnly(t)  
  183.         local proxy = {}  
  184.         local mt = {  
  185.             __index = t,  
  186.             __newindex = function(t, k, v)  
  187.                 error("attempt to update a read-only table", 2)  
  188.             end  
  189.         }  
  190.         setmetatable(proxy, mt)  
  191.         return proxy  
  192.     end  
  193.     days = readOnly {"Sunday""Monday""Tuesday""Wednesday""Thursday""Friday""Saturday"}  
  194.     print(days[1])   
  195. --  days[2] = "Noday"   
  196. end  
  197.   
  198. local function objectTest()  
  199.     local Account = {  
  200.         balance = 0,  
  201.         new = function(self, o)  
  202.             o = o or {} -- create table is user does not provide one   
  203.             setmetatable(o, self)  
  204.             self.__index = self  
  205.             return o  
  206.         end,  
  207.         withdraw = function(self, v)  
  208.             if v>self.balance then error"insufficient funds" end  
  209.             self.balance = self.balance - v  
  210.         end,  
  211.         deposit = function(self, v)  
  212.             self.balance = self.balance + v  
  213.         end  
  214.     }  
  215.       
  216.     local a = Account:new {balance = 0}  
  217.     a:deposit(100.00)  
  218.     print(a.balance)  
  219.     local b = Account:new()  
  220.     print(b.balance)  
  221.     b.balance = 123  
  222.     print(b.balance)  
  223.     b:withdraw(100)  
  224.     print(b.balance)  
  225.     print(a.balance)  
  226.       
  227.       
  228.     -- inheritance   
  229.     local SpecialAccount = Account:new({  
  230.         withdraw = function(self, v)  
  231.             if v - self.balance >= self:getLimit() then  
  232.                 error"insufficient funds"  
  233.             end  
  234.             self.balance = self.balance - v  
  235.         end,   
  236.         getLimit = function(self)   
  237.             return self.limit or 0  
  238.         end  
  239.     })  
  240.       
  241.     local s = SpecialAccount:new {limit=1000.00}  
  242.     s:deposit(100.00)  
  243.     s:withdraw(200.00)  
  244.     print("s:", s.balance)  
  245. end  
  246.   
  247.   
  248. local function main()  
  249.     languageTest();  
  250.     tableTest();  
  251.     objectTest();  
  252. end  
  253. main()  
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*s1)
	
	s1 = Set.new {10, 4, 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,
			__newindex = function(t, k, 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()


 

你可能感兴趣的:(脚本语言)