Lua 函数

【1】函数定义

Lua函数定义格式如下:

11 optional_function_scope function function_name(argument1, argument2, argument3..., argumentn) 22 function_body 33 return result_params_comma_separated 44 end

解析:

optional_function_scope: 该参数是可选的,指定函数是全局函数还是局部函数。

未设置该参数默认为全局函数,如果你需要设置函数为局部函数需要使用关键字 local。

function_name: 指定函数名称。

argument1, argument2, argument3..., argumentn: 函数参数,多个参数以逗号隔开,函数也可以不带参数。

function_body: 函数体,函数中需要执行的代码语句块。

result_params_comma_separated: 函数返回值,Lua语言函数可以返回多个值,每个值以逗号隔开。

【2】Lua函数示例

函数示例

1 1 --[[ 函数返回两个值的最大值 --]] 2 2 local function max(num1, num2) 3 3 if (num1 > num2) then 4 4 result = num1; 5 5 else 6 6 result = num2; 7 7 end 8 8 9 9 return result; 1010 end 1111 1212 -- 调用函数 1313 print("两值比较最大值为 (10, 4) :: ", max(10, 4)) 1414 print("两值比较最大值为 (5, 6) :: ", max(5, 6)) 1515 1616 1717 --[[ 1818 两值比较最大值为 (10, 4) :: 10 1919 两值比较最大值为 (5, 6) :: 6 2020 ]]

【3】Lua函数特色

(1)将函数作为参数传递给函数。示例如下:

1 1 --[[将函数作为参数传递给函数]] 2 2 myprint = function(param) 3 3 print("这是打印函数 - ##", param, "##") 4 4 end 5 5 6 6 function add(num1, num2, functionPrint) 7 7 result = num1 + num2 8 8 -- 调用传递的函数参数 9 9 functionPrint(result) 1010 end 1111 1212 myprint(10) 1313 -- myprint 函数作为参数传递 1414 add(2, 5, myprint) 1515 1616 --[[ 1717 这是打印函数 - ## 10 ## 1818 这是打印函数 - ## 7 ## 1919 ]]

(2)函数可以返回多个值

例1,代码如下:

1 1 --[[例如:string.find 其返回匹配串“开始和结束的下标”(如果不存在匹配串返回nil)]] 2 2 s, e = string.find("http://www.baidu.com", "baidu") 3 3 print(s, e) 4 4 5 5 --[[执行结果 6 6 12 16 7 7 ]] 8 8 9 9 s, e = string.find("http://www.google.com", "baidu") 1010 print(s, e) 1111 1212 --[[执行结果 1313 nil nil 1414 ]]

例2,代码如下:

1 1 --[[return后列出要返回值的列表即可返回多值]] 2 2 function maximum (a) 3 3 local mi = 1 -- 最大值索引 4 4 local m = a[mi] -- 最大值 5 5 for i,val in ipairs(a) do 6 6 if val > m then 7 7 mi = i 8 8 m = val 9 9 end 1010 end 1111 return m, mi 1212 end 1313 1414 print(maximum({8, 10, 23, 12, 5})) 1515 1616 --[[执行结果 1717 23 3 1818 ]]

例3,特殊函数unpack,它可以接受一个数组作为参数,并从下标1开始返回该数组的所有元素:

1 print(unpack{10, 20, 30})  -- 10  20  30

(3)不定形参函数

3.1 自定义不定形参函数:Lua函数可以接收可变数目的参数

11 function add(...) 22 local s = 0 33 for i, v in ipairs{...} do -- {...} 表示一个由所有变长参数构成的数组 44 s = s + v 55 end 66 return s 77 end 88 99 print(add(3, 4, 5, 6, 7)) -- 25

3.2 将可变参数赋值给一个变量

1 1 --[[将可变参数赋值给一个变量]] 2 2 function average(...) 3 3 result = 0 4 4 local arg = {...} -- arg 为一个表,局部变量 5 5 for i,v in ipairs(arg) do 6 6 result = result + v 7 7 end 8 8 print("总共传入 " .. #arg .. " 个数") 9 9 return result / #arg 1010 end 1111 1212 print("平均值为", average(10, 5, 3, 4, 5, 6)); 1313 1414 --[[执行结果 1515 总共传入 6 个数 1616 平均值为 5.5 1717 ]]

3.3 可以通过select("#", ...来获取可变参数的数量)

1 1 --[[可以通过 select("#",...) 来获取可变参数的数量]] 2 2 function average(...) 3 3 result = 0 4 4 local arg = {...} 5 5 for i, v in ipairs(arg) do 6 6 result = result + v 7 7 end 8 8 print("总共传入 " .. select("#", ...) .. " 个数") 9 9 return result / select("#", ...) 1010 end 1111 1212 print("平均值为", average(10, 5, 3, 4, 5, 6)) 1313 1414 --[[执行结果 1515 总共传入 6 个数 1616 平均值为 5.5 1717 ]]

3.4 需要几个固定参数再加上可变参数时,固定参数必须放在可变参数之前

1 1 function fwrite(fmt, ...) -- 固定的参数fmt 2 2 return io.write(string.format(fmt, ...)) 3 3 end 4 4 5 5 fwrite("baidu\n") -- fmt = "baidu", 没有变长参数。 6 6 fwrite("%d%d\n", 1, 2) -- fmt = "%d%d", 变长参数为 12 7 7 8 8 --[[执行结果 9 9 baidu 1010 12 1111 ]]

3.5 遍历变长参数时只需要使用{...},然而变长参数可能会包含一些nil,那么就需要用select函数来访问变长参数。

[1] select('#', ...)返回可变参数的长度

[2] select(n, ...)用于访问n到select('#', ....)的参数

1 1 --[[ 2 2 遍历变长参数的时候只需要使用{},然而变长参数可能会包含一些nil,那么就可以用select函数来访问变长参数了:select('#',) 或者 select(n,) 3 3 select('#',) 返回可变参数的长度 4 4 select(n,) 用于访问 n 到 select('#',) 的参数 5 5 ]] 6 6 7 7 do 8 8 function foo(...) 9 9 for i = 1, select('#', ...) do --> 获取参数总数 1010 local arg = select(i, ...); --> 读取参数 1111 print("arg", arg); 1212 end 1313 end 1414 1515 foo(11, 12, 13, 14); 1616 end 1717 1818 --[[执行结果 1919 arg 11 2020 arg 12 2121 arg 13 2222 arg 14 2323 ]]

(4)具名实参

具名实参,即具体名称的实参值。比如,字符串拷贝函数有两个参数(src, dest),当我们记不清第一个参数是src还是dest时,可以在调用时明确指明具体实参值。

Lua语言中的rename接口,就是个很有代表性的例子。试着新建一个文件temp.lua,然后复制以下代码段:

11 function rename(arg) 22 return os.rename(arg.old, arg.new) 33 end 44 55 rename({old = "temp.lua", new = "temp1.lua"}) 66 --rename({new = "new1.lua", old = "temp1.lua"})

注意观察:执行结果,同目录下会多一个temp1.lua文件

再把第六行的注释去掉,然后执行结果:同目录下会多一个new1.lua文件。

(5)待续

【4】深入函数

(1)闭合函数

[1.1] 在Lua中,函数是第一类值

如何理解这个“第一类值”?类比着学习,我们知道C语言的数据类型有整数、浮点数、枚举、指针、数组、结构、共用体、void等等。

前面我们也学习了《Lua数据类型》包括nil、boolean、number、string、function等等。

即就是,在Lua中,函数可以存储到变量(无论全局变量还是局部变量)中或table中,可以作为实参传递给其他函数,还可以作为其他函数的返回值。

先看最常见的这个求和函数定义:

1 function func(a, b) return a + b end

其等价于

1 func = function(a, b) return a + b end

两种方式比较:

第一种方式,似乎更符合我们对函数的潜意识(传统的)视觉印象规则。

第二种方式,更彰显了Lua中函数作为“第一类值”的体现和范畴。

通过以上两种方式的对比,我们可以更深入的理解Lua中函数的定义本质:

一个函数定义实质上是一条赋值语句,创建了一种类型为“函数”的值,且将其赋值于变量func。

可以验证一下类型,如下所示:

11 func = function(a, b) return a + b end 22 print(func) -- function: 02DF8FC8 33 print(type(func)) -- function 44 print(func(10, 20)) -- 30

在Lua中,将表达式“function(x) <body> end”视为一种函数的构造式,就像table的构造式{ }一样。

将这种函数构造式的结果称为一个“匿名函数”,虽然一般情况下,会将函数赋予全局变量,即给予其一个名称。

但是,在某些特殊情况下,仍会需要直接用到匿名函数。

不要问我哪里需要用到,其实你肯定见过,比如sort函数,请看如下示例:

1 1 students = 2 2 { 3 3 {name = "Wang", age = "18"}, 4 4 {name = "Qin", age = "20" }, 5 5 {name = "Li", age = "19"}, 6 6 {name = "Wei", age = "21"}, 7 7 } 8 8 9 9 --[[ before sort ::]] 1010 print("before sort ::") 1111 for i = 1, #students do 1212 print(i, students[i].name, students[i].age) 1313 end 1414 1515 table.sort(students, function(a, b) return (a.name > b.name) end) 1616 1717 --[[ after sort ::]] 1818 print("after sort ::") 1919 for k, v in pairs(students) do 2020 print(k, v.name, v.age) 2121 end 2222 2323 --[[执行结果 2424 before sort :: 2525 1 Wang 18 2626 2 Qin 20 2727 3 Li 19 2828 4 Wei 21 2929 after sort :: 3030 1 Wei 21 3131 2 Wang 18 3232 3 Qin 20 3333 4 Li 19 3434 ]]

像sort这样的函数,接受另一个函数作为实参,称其是一个“高阶函数”,是一种强大的编程机制。

1 1 names = {"Peter", "Paul", "Mary"} 2 2 grades = {Mary = 10, Paul = 7, Peter = 8} 3 3 table.sort(names, function(n1, n2) 4 4 return grades[n1] > grades[n2] 5 5 end) 6 6 7 7 for k, v in ipairs(names) do 8 8 print(k, v) 9 9 end 1010 1111 --[[ 1212 1 Mary 1313 2 Peter 1414 3 Paul 1515 ]] 1616 1717 names = {"Peter", "Paul", "Mary"} 1818 grades = {Mary = 10, Paul = 7, Peter = 8} 1919 2020 function sortbygrade(names, grades) 2121 table.sort(names, function(n1, n2) 2222 return grades[n1] > grades[n2] 2323 end) 2424 return names 2525 end 2626 2727 for k, v in ipairs(sortbygrade(names, grades)) do 2828 print(k, v) 2929 end 3030 3131 --[[ 3232 1 Mary 3333 2 Peter 3434 3 Paul 3535 ]] 3636 3737 --[[一般函数]] 3838 function increCounter1() 3939 local i = 0 4040 i = i + 1 4141 return i 4242 end 4343 4444 print(increCounter1) -- function: 02A6B8F8 4545 print(increCounter1()) -- 1 4646 print(increCounter1()) -- 1 4747 4848 --[[闭合函数]] 4949 function increCounter2() 5050 local i = 0 5151 return function() 5252 i = i + 1 5353 return i 5454 end 5555 end 5656 5757 print(increCounter2) -- function: 02A6B738 5858 print(increCounter2()) -- function: 02A6B918 5959 6060 c1 = increCounter2() 6161 print(c1()) -- 1 6262 print(c1()) -- 2 6363 c2 = increCounter2() 6464 print(c2()) -- 1 6565 print(c1()) -- 3 6666 print(c2()) -- 2 6767 6868 --[[闭合函数 局部变量]] 6969 function increCounter3() 7070 return function() 7171 local i = 9 7272 i = i + 1 7373 return i 7474 end 7575 end 7676 7777 print(increCounter3) -- function: 02A6B6F8 7878 print(increCounter3()) -- function: 02A6B7D8 7979 8080 c3 = increCounter3() 8181 print(c3()) -- 10 8282 print(c3()) -- 10 8383 c4 = increCounter3() 8484 print(c4()) -- 10 8585 print(c4()) -- 10 8686 print(c4()) -- 10

匿名函数

(2)非全局函数

(3)正确尾调用

【5】总结

Good Good Study, Day Day Up.

顺序 选择 循环 总结

点赞
收藏

评论区

加载中...

相关推荐

MySQL:[Err] 1292 - Incorrect datetime value: ‘0000-00-00 00:00:00‘ for column ‘CREATE_TIME‘ at row 1

文章目录问题用navicat导入数据时,报错:原因这是因为当前的MySQL不支持datetime为0的情况。解决修改sql\mode:sql\mode:SQLMode定义了MySQL应支持的SQL语法、数据校验等,这样可以更容易地在不同的环境中使用MySQL。全局s

Oracle 分组与拼接字符串同时使用

SELECTT.,ROWNUMIDFROM(SELECTT.EMPLID,T.NAME,T.BU,T.REALDEPART,T.FORMATDATE,SUM(T.S0)S0,MAX(UPDATETIME)CREATETIME,LISTAGG(TOCHAR(

MySQL部分从库上面因为大量的临时表tmp_table造成慢查询

背景描述Time:20190124T00:08:14.70572408:00User@Host:@Id:Schema:sentrymetaLast_errno:0Killed:0Query_time:0.315758Lock_

皕杰报表之UUID

​在我们用皕杰报表工具设计填报报表时,如何在新增行里自动增加id呢?能新增整数排序id吗?目前可以在新增行里自动增加id,但只能用uuid函数增加UUID编码,不能新增整数排序id。uuid函数说明:获取一个UUID,可以在填报表中用来创建数据ID语法:uuid()或uuid(sep)参数说明:sep布尔值,生成的uuid中是否包含分隔符'',缺省为

手写Java HashMap源码

HashMap的使用教程HashMap的使用教程HashMap的使用教程HashMap的使用教程HashMap的使用教程22

2020年前端实用代码段,为你的工作保驾护航

有空的时候,自己总结了几个代码段,在开发中也经常使用,谢谢。1、使用解构获取json数据let jsonData  id: 1,status: "OK",data: 'a', 'b';let  id, status, data: number   jsonData;console.log(id, status, number )