Lua 函数function
来源:互联网 发布:js判断ie版本是否大于8 编辑:程序博客网 时间:2024/04/30 14:51
Lua 函数function
note 目录
- lua函数定义,声明,调用
- lua函数参数
- lua函数返回值
- 深入lua函数
1:Lua 函数定义和声明
【定义】
在lua中,函数是一种对语句和表达式进行封装抽象的主要机制。函数既可以完成默写特定的任务,也可以只做一些计算并返回结果。
【声明】
function func(arg1,arg2) ... 函数体 ... return(可选) end
【调用】
函数的调用与C语言基本上一样的。唯一有差别的是如果函数参数只有一个参数,并且这个参数是字符串常量或是table的构造器,那么圆括号就可以省略圆括号。
example:print "hello world" <---> print("hello wrold")func {x = 10 , y = 20 } <---> func({x = 20 , y = 30})
2:Lua 函数参数
- 按值传递
- 按引用传递
- 变长参数
- 具名参数
2.1 按值传递
2.1.1:形参和实参个数一致
lua中的按值传递和C语言的基本是一样的,实参传递给形参,实参和形参就没有关系了,形参的改变不会影响到实参,典型的就是swap
函数。
local function swap(a,b) local temp = a a = b b = temp print(a,b)endlocal x = 1local y = 2print("before swap")print(x,y)print("swap")swap(x,y)print("after swap")print(x,y)output:before swap:12swap:21after swap12
2.1.2:实参和形参个数不一致,lua会自动调整实参个数,调整规则分为2种情况。
【1】实参个数 > 形参个数
从左向右,多余的实参会被忽略。
【2】实参个数 < 形参个数
从左向右,没有被实参初始化的形参会被赋值为nil
local function func1(a,b) print(a,b)endlocal function func2(a,b,c,d) print(a,b,c,d)endlocal x =1local y = 2local z = 3print("实参个数 > 形参个数")func1(x,y,z)print("实参个数 < 形参个数")func2(x,y,z)output:实参个数 > 形参个数12实参个数 < 形参个数123nil
2.2 按引用传递
当函数参数是table类型的时候,传递进来的是实参的引用,此时,函数内部改变了table里面的值,会该改变调用者传递进来的实际参数。
local function ChangeTable(tab) tab.x = tab.x + 10 tab.y = tab.y + 20endlocal a = {x = 10,y = 20}print("before changeTab")print(a)ChangeTable(a)print("after changeTab")print(a)output:before changeTab1020after changeTab2040
2.3 变长参数
lua中可以接受不定长度的参数。用...
标识,表示该函数可以接受不同长度的参数。
local function func(...) local tempTab = {...} local str = table.contat(tempTab , " ") print(str)endfunc(1,2,3)func(1,2,3,4,5)output:1 2 3 1 2 3 4 5
2.4 具名参数
传递参数时,使得实参具有名称的实际参数。
【引入具名参数概念的目的】
Lua中参数传递机制是通过位置来传递的。也就是说早调用一个函数时,实参通过他在参数中位置来与形参匹配起来的。第一个实参值与第一个形参值匹配,依次类推。这种方式缺点就是在外界调用的时候不能自定义实参的位置,一定要按照形参的意义来。通常会忘记第一参数和第二个参数…第n个参数分别代表什么。因此会希望这个函数能接受具有名称的实参。例如:
--无效的演示代码rename(old = "temp.lua" , new = "temp1.lua")
【可以用到具名参数的2个条件】
(1)lua中并不能支持这种语法,但可以通过细微的改变来获得相同的效果。主要是所有的实参组织到一个table
中,并将这个table
作为唯一的实参传给函数。
(2)另外,还需要用到一种Lua中特殊函数调用语法,就是当实参只有一个table
构造式时,函数调用中的圆括号是可有可无的。
rename{old = "temp.lua" , new = "temp1.lua"}
【具名参数的函数定义】
可以用具名参数的函数在定义时。形参只能定义一个参数,并且这个参数是table
类型。
function rename(arg) return os.rename(arg.old , arg.new)end
3:Lua 函数的返回值
lua具有一项非常与众不同的特性,允许函数返回多个结果。Lua中的一些库函数就是如此的。
example:
使用库函数 string.find
,在源字符串中查找目标字符串,若查找成功,则返回目标字符串在源字符串中的起始位置和结束位置的下标。
local s, e = string.find("hello world", "llo")print(s, e)output35
【返回多值定义】
只需要在return
关键字后列出所有的返回值即可。
example:查找一个数组中的最大元素,并返回该元素的位置
function Max(a) local mi = 1 --最大值的索引 local m = a[mi] for i , value in ipairs(a) do if val > m then mi = i m = value end end return m,miendprint(Max({8,10,23,12,5}))output:233
【根据实际调用来返回对少个值】
Lua会调整一个函数的返回值数量来适用不同的情况。
(1)若将函数调用作为一条单独语句时,Lua会丢弃函数的所有返回值。
(2)若将函数作为表达式的一部分来调用时,Lua只保留函数的第一返回值。
(3)只有当一个函数调用是一系列表达式中的最后一个元素(或仅有一个元素)时,才能获得它的所有返回值。这里的所谓的“一系列”在Lua中表现为4种情:
接下来分别介绍这4种情况,首先,定义这些函数:
function foo0()end --无返回结果function foo1() return "a" end --返回1个结果function foo2() return "a" ,"b" end --返回2个结果
a:在多重赋值中(分为3种情况)
若一个函数调用是最后的(或仅有的)一个表达式,那么Lua会保留其尽可能多的返回值,用于匹配赋值变量。
x,y = foo2() --> x = "a" , y = "b"x = foo2() --> x = "a" , "b"被丢弃x,y,z = 10,foo2() --> x = 10, y = "a" , z = "b"
若一个函数没有返回值或者没有足够多的返回值,那么Lua会用nil来补充缺失的值
x,y = foo0() --> x = nil , y = nilx,y = foo1() --> x = "a" , y = nilx,y,z = foo2() --> x = "a" , y = "b" , z = nil
若一个函数调用不是一系列表达式的最后一个元素,那么将只会产生一个值。
x,y = foo2(),20 --> x = "a" , y = 20x,y = foo0() , 20 ,30 --> x = nil , y = 20 , 30被丢弃
b:当一个函数调用作为另外一个函数调用的最后一个(或仅有的)实参时,第一个参数的所有返回值都将作为实参传入第二个函数。
print(foo0()) -->print(foo1()) -->aprint(foo2()) -->a bprint(foo2(),1) -->a 1print(foo2() .. "x") -->ax
当foo2出现在一个表达式中,Lua会将返回值调整为1,因此在上面的最后一行中,只有”a”参与了字符串的连接的操作。
c:table构造式可以完整地接收一个函数调用的所有的结果,即不会有任何数量方面的调整:
t = { foo0() } --> t = {} (一个空的table)t = { foo1() } --> t = {"a"}t = { foo2() } --> t = {"a" , "b"}
不过,这种table的行为只有当一个函数调用作为最后一个元素是才会发生,而在其他位置上的函数调用总是产生一个结果值。
t = {foo0(),foo2(),4} --> t[1] = nil , t[2] = "a" , t[3] = 4
d:最后一种情况是return语句,如return f()
这样的语句将返回f的所有值:
function foo(i) if i == 0 then foo0() elseif i == 1 then return foo1() elseif i == 2 then retrun foo2() endendprint(foo(1)) --> aprint(foo(2)) --> a bprint(foo(0)) --> 无返回值print(foo(3)) --> 无返回值
【unpack函数】
unpack(tab)
它接收一个数组作为参数,并从下标1开始返回该数组的所有的元素:
print(unpack{10,20,30}) --> 10,20,30
a,b = unpack{10,20,30} --> a = 10 , b =20 30被丢弃
4:深入lua函数
在Lua中,函数与所有的其他值一样的都是匿名的,即他们都没有名称,操作的都是持有该函数的变量。
a = {p = print}a.p("hello world") -->hello worldprint = math.sin -->print现在引用了正弦函数a.p(print(1)) -->0.841470sin = a.p -->sin现在引用了print函数sin(10 , 20) -->10 20
最常见的函数编写方式:直接给出函数名
function foo(x) return 2*xend
另外一种是在声明函数时赋值给一个变量
local foo = funtion(x) return 2*x end
因此,一个函数定义实际就是一条语句(一条赋值语句),这条语句创建了一种类型为“函数”的值,并将这个值赋予一个变量。
可以将表达式function(x)<body>end
视为一种函数的构造式,就像table
的构造式{}
一样。将这种函数构造式的结果称为一个“匿名函数”。
4.1 closure(闭合函数)
将一个函数写在另一个函数之内,那么位于内部的函数便可以访问外部函数中的局部变量,这项特征称为“词法域”。
function newCounter() local i = 0 return function() --匿名函数 i = i + 1 return i end endlocal c1 = newCounter()print(c1()) -->output : 1print(c1()) -->output : 2
在上面的示例中,我们将newCounter()函数称为闭包函数。其函数体内的局部变量i被称为”非局部变量”,和普通局部变量不同的是该变量被newCounter函数体内的匿名函数访问并操作。再有就是在函数newCounter返回后,其值仍然被保留并可用于下一次计算。再看一下下面的调用方式。
local c2 = newCounter()print(c2()) --> 1print(c1()) --> 3print(c2()) --> 2
由此可以推出,Lua每次在给新的闭包变量赋值时,都会让不同的闭包变量拥有独立的”非局部变量”。
4.2 non-global function(非全局的函数)
函数不仅可以存储在全局变量中,还可以存储在table
字段中和局部变量中。
大部分Lua库也采用了这种机制(io.read , math.sin)。
若要在lua中创建这种函数,只需要将常规的函数与table结合起来使用即可:
Lib = {}Lib.foo = function (x , y) return x + y endLib.goo = function (x , y) return x - y end
也可以使用table
的构造式
Lib = {foo = = function (x , y) return x + y end,goo = function (x , y) return x - y end}
除此之外,lua还提供了另外一种语法来定义这类函数
Lib = {}function Lib.foo = function (x , y) return x + y endfunction Lib.goo = function (x , y) return x - y end
只要将一个函数存储到一个局部变量中,即得到了一个“局部函数(local function)”,也就是该函数只能在某个特定的作用域中使用。不加local的函数就会添加到全局表_G
里面。
局部函数语法:
local function foo(<参数>) <函数体> end
Lua将其展开为:
local foofoo = function (<参数>) <函数体> end
4.3 proper tail call(正确的尾调用)
Lua中的函数有一个有趣的特征,就是Lua支持“尾调用消除(tail-call elimination)”。
所谓“尾调用(tail call)“就是一种类似与goto
的函数调用。
当一个函数调用是另外一个函数的最后一个动作时,该调用才算是一个“尾调用”
function f(x) return g(x)end
由于g(x)函数是f(x)函数的最后一条语句,在函数g返回之后,f()函数将没有任何指令需要被执行,因此在函数g()返回时,可以直接返回到f()函数的调用点。由此可见,Lua解释器一旦发现g()函数是f()函数的尾调用,那么在调用g()时将不会产生因函数调用而引起的栈开销。这里需要强调的是,尾调用函数一定是其调用函数的最后一条语句,否则Lua不会进行优化。然而事实上,我们在很多看似是尾调用的场景中,实际上并不是真正的尾调用,如:
function f(x) g(x) end --没有return语句的明确提示function f(x) return g(x) + 1 --在g()函数返回之后仍需执行一次加一的指令。function f(x) return x or g(x) --如果g()函数返回多个值,该操作会强制要求g()函数只返回一个值。function f(x) return (g(x)) --原因同上。
在Lua中,只有“return ()”形式才是标准的尾调用,至于参数中(args)是否包含表达式,由于表达式的执行是在函数调用之前完成的,因此不会影响该函数成为尾调用函数。
- Lua 函数function
- lua学习笔记---Function(函数)
- Lua 标准库 - 基本函数(base function)
- Lua 标准库 - 基本函数(base function)
- Lua 标准库 - 基本函数(base function)
- Lua 标准库 - 基本函数(base function)
- Lua 标准库 - 基本函数(base function)
- Lua 标准库 - 基本函数(base function)
- Lua标准库 - 基本函数(base function)
- Lua 标准库 - 基本函数(base function)
- Lua 标准库 - 基本函数(base function)
- Lua 标准库 - 基本函数(base function)
- Lua 标准库 - 基本函数(base function)
- lua function
- Lua function
- lua-function
- lua function
- Lua function函数,可变参数, 局部函数,尾递归优化
- Karbor全面使能OpenStack云数据保护
- hdu 1028带来的启示
- hadoop 2.7.3 集群模式
- Tomcat服务器学习和使用
- Codeforces Round #419
- Lua 函数function
- scikit-learn 中的随机森林用法
- 观点:深度学习,先跟上再说
- 线程
- Linux下搭建集群环境(2)-----------linux下安装Mysql
- cloudera反向解析问题
- Codeforces Round #419 (Div. 2)
- node.js多种路由功能
- codeforces Karen and Coffee (区间贡献 思维)