您的位置:首页 > 编程语言 > Lua

lua-function

2015-12-23 17:17 375 查看

分类:

lua(8)


第五章 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 printHello(a,b)  --a,b为参数
print(a,b);
print("Hello")
end

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

testFuction=function (a,b) return a+b end
--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)本身,所以不是尾函数

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, 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()

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, 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()
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: