• Lua 函数


    【1】函数定义

    Lua函数定义格式如下:

    1 optional_function_scope function function_name(argument1, argument2, argument3..., argumentn)
    2     function_body
    3 return result_params_comma_separated
    4 end

    解析:

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

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

    function_name: 指定函数名称。

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

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

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

    【2】Lua函数示例

    函数示例

     1 --[[ 函数返回两个值的最大值 --]]
     2 local function max(num1, num2)
     3    if (num1 > num2) then
     4       result = num1;
     5    else
     6       result = num2;
     7    end
     8 
     9    return result;
    10 end
    11 
    12 -- 调用函数
    13 print("两值比较最大值为 (10, 4) :: ", max(10, 4))
    14 print("两值比较最大值为 (5, 6) :: ", max(5, 6))
    15 
    16 
    17 --[[
    18 两值比较最大值为 (10, 4) :: 10
    19 两值比较最大值为 (5, 6) ::     6
    20 ]]

    【3】Lua函数特色

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

     1 --[[将函数作为参数传递给函数]]
     2 myprint = function(param)
     3    print("这是打印函数 - ##", param, "##")
     4 end
     5 
     6 function add(num1, num2, functionPrint)
     7    result = num1 + num2
     8    -- 调用传递的函数参数
     9    functionPrint(result)
    10 end
    11 
    12 myprint(10)
    13 -- myprint 函数作为参数传递
    14 add(2, 5, myprint)
    15 
    16 --[[
    17 这是打印函数 - ##    10    ##
    18 这是打印函数 - ##    7    ##
    19 ]]

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

    例1,代码如下:

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

    例2,代码如下:

     1 --[[return后列出要返回值的列表即可返回多值]]
     2 function maximum (a)
     3     local mi = 1             -- 最大值索引
     4     local m = a[mi]          -- 最大值
     5     for i,val in ipairs(a) do
     6        if val > m then
     7            mi = i
     8            m = val
     9        end
    10     end
    11     return m, mi
    12 end
    13 
    14 print(maximum({8, 10, 23, 12, 5}))
    15 
    16 --[[执行结果
    17 23    3
    18 ]]

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

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

    (3)不定形参函数

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

    1 function add(...)
    2 local s = 0
    3   for i, v in ipairs{...} do   -- {...} 表示一个由所有变长参数构成的数组
    4     s = s + v
    5   end
    6   return s
    7 end
    8 
    9 print(add(3, 4, 5, 6, 7))  -- 25

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

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

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

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

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

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

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

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

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

     1 --[[
     2 遍历变长参数的时候只需要使用{…},然而变长参数可能会包含一些nil,那么就可以用select函数来访问变长参数了:select('#', …) 或者 select(n, …)
     3 select('#', …) 返回可变参数的长度
     4 select(n, …) 用于访问 n 到 select('#',…) 的参数
     5 ]]
     6 
     7 do
     8     function foo(...)
     9         for i = 1, select('#', ...) do  --> 获取参数总数
    10             local arg = select(i, ...); --> 读取参数
    11             print("arg", arg);
    12         end
    13     end
    14 
    15     foo(11, 12, 13, 14);
    16 end
    17 
    18 --[[执行结果
    19 arg    11
    20 arg    12
    21 arg    13
    22 arg    14
    23 ]]

    (4)具名实参

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

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

    1 function rename(arg)
    2     return os.rename(arg.old, arg.new)
    3 end
    4 
    5 rename({old = "temp.lua", new = "temp1.lua"})
    6 --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。

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

    1 func = function(a, b) return a + b end
    2 print(func)            -- function: 02DF8FC8
    3 print(type(func))      -- function
    4 print(func(10, 20))    -- 30

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

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

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

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

     1 students =
     2 {
     3     {name = "Wang", age = "18"},
     4     {name = "Qin", age = "20" },
     5     {name = "Li", age = "19"},
     6     {name = "Wei", age = "21"},
     7 }
     8 
     9 --[[ before sort ::]]
    10 print("before sort ::")
    11 for i = 1, #students do
    12     print(i, students[i].name, students[i].age)
    13 end
    14 
    15 table.sort(students, function(a, b) return (a.name > b.name) end)
    16 
    17 --[[ after sort ::]]
    18 print("after sort ::")
    19 for k, v in pairs(students) do
    20     print(k, v.name, v.age)
    21 end
    22 
    23 --[[执行结果
    24 before sort ::
    25 1    Wang    18
    26 2    Qin    20
    27 3    Li    19
    28 4    Wei    21
    29 after sort ::
    30 1    Wei    21
    31 2    Wang    18
    32 3    Qin    20
    33 4    Li    19
    34 ]]

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

     1 names = {"Peter", "Paul", "Mary"}
     2 grades = {Mary = 10, Paul = 7, Peter = 8}
     3 table.sort(names, function(n1, n2)
     4     return grades[n1] > grades[n2]
     5     end)
     6 
     7 for k, v in ipairs(names) do
     8     print(k, v)
     9 end
    10 
    11 --[[
    12 1    Mary
    13 2    Peter
    14 3    Paul
    15 ]]
    16 
    17 names = {"Peter", "Paul", "Mary"}
    18 grades = {Mary = 10, Paul = 7, Peter = 8}
    19 
    20 function sortbygrade(names, grades)
    21     table.sort(names, function(n1, n2)
    22     return grades[n1] > grades[n2]
    23     end)
    24     return names
    25 end
    26 
    27 for k, v in ipairs(sortbygrade(names, grades)) do
    28     print(k, v)
    29 end
    30 
    31 --[[
    32 1    Mary
    33 2    Peter
    34 3    Paul
    35 ]]
    36 
    37 --[[一般函数]]
    38 function increCounter1()
    39    local i =  0
    40     i = i + 1
    41     return i
    42 end
    43 
    44 print(increCounter1)     -- function: 02A6B8F8
    45 print(increCounter1())   -- 1
    46 print(increCounter1())   -- 1
    47 
    48 --[[闭合函数]]
    49 function increCounter2()
    50    local i =  0
    51    return function()
    52             i = i + 1
    53             return i
    54         end
    55 end
    56 
    57 print(increCounter2)    -- function: 02A6B738
    58 print(increCounter2())  -- function: 02A6B918
    59 
    60 c1 = increCounter2()
    61 print(c1())            -- 1
    62 print(c1())            -- 2
    63 c2 = increCounter2()
    64 print(c2())            -- 1
    65 print(c1())            -- 3
    66 print(c2())            -- 2
    67 
    68 --[[闭合函数 局部变量]]
    69 function increCounter3()
    70    return function()
    71         local i = 9
    72         i = i + 1
    73         return i
    74     end
    75 end
    76 
    77 print(increCounter3)    -- function: 02A6B6F8
    78 print(increCounter3())  -- function: 02A6B7D8
    79 
    80 c3 = increCounter3()
    81 print(c3())            -- 10
    82 print(c3())            -- 10
    83 c4 = increCounter3()
    84 print(c4())            -- 10
    85 print(c4())            -- 10
    86 print(c4())            -- 10

    匿名函数

    (2)非全局函数

    (3)正确尾调用

    【5】总结

    Good Good Study, Day Day Up.

    顺序 选择 循环 总结

  • 相关阅读:
    UVA 1152 4 Values whose Sum is 0
    IOI 2006 Pyramid
    CTSC 2000 冰原探险
    IOI 2009 Mecho
    IOI 2011 Rice Hub 米仓
    NOIP 2013 火柴排队 程序
    USACO 2004 MooFest 奶牛集会
    USACO Training Section 3.1 Contact
    动态加载Ribbon功能区
    Ribbon2: 创建动态的Ribbon库
  • 原文地址:https://www.cnblogs.com/Braveliu/p/9682669.html
Copyright © 2020-2023  润新知