Lua_函数_多返回值_可变参数_闭包_非全局函数_尾调用(7)

目录

码云代码链接
https://gitee.com/wenwenc9/lua_pro.git

Lua 提供了许多的内建函数

Lua 函数主要有两种用途:
1.完成指定的任务,这种情况下函数作为调用语句使用;
2.计算并返回值,这种情况下函数作为赋值语句的表达式使用。

Lua 编程语言函数定义格式如下:

optional_function_scope function function_name( argument1, argument2, argument3..., argumentn)
   function_body
 return result_params_comma_separated
end

解析:

  • optional_function_scope
    : 该参数是可选的制定函数是全局函数还是局部函数?未设置该参数默认为全局函数,如果你需要设置函数为局部函数需要使用关键字 local。
    fucntion 声明函数所用
  • function_name:
    指定函数名称。
  • argument1, argument2, argument3..., argumentn:
    函数参数,多个参数以逗号隔开,函数也可以不带参数。
  • function_body:
    函数体,函数中需要执行的代码语句块。
  • result_params_comma_separated:
    函数返回值,Lua语言函数可以返回多个值,每个值以逗号隔开。

一、例子

function max(num1,num2)
    if (num1 > num2) then
        result = num1;
    else
        result = num2;
    end
    return result
end

print('两个比较最大值为',max(10,4))
print('两个比较最大值为',max(5,6))

二、多返回值

string.find:返回匹配串"开始和结束的下标"(如果不存在匹配串返回nil)

s, e = string.find("www.abc12345.cn", "ab")
print(s, e) -- 5 13

设定最大值为8,如果v大于8则返回

function maximum(a)
    local mi = 1  -- 最大值索引
    local m = a[mi] -- 最大值  8
    for i, val in ipairs(a) do
        if val > m then
            mi = i
            m = val
        end
    end
    return m, mi
end
print(maximum({ 8, 10, 23, 12, 5 }))

三、可变参数-万能参数

Lua函数可以接受可变数目的参数,和C语言类似在函数参数列表中使用三点(…) 表示函数有可变的参数,除了参数以外,arg表中还有一个域 n 表示参数的个数
Lua将函数的参数放在一个叫arg的表中,#arg 表示传入参数的个数。

例如,我们计算几个数的平均值:

function average(...)
   result = 0
   local arg={...}
   for i,v in ipairs(arg) do -- 累计求和
      result = result + v
   end
   print("总共传入 " .. #arg .. " 个数")
   return result/#arg
end

print("平均值为",average(10,5,3,4,5,6))
总共传入 6 个数
平均值为	5.5

例如,我们可以重写 print 函数:

printResult = ""
function print(...)
    for i,v in ipairs(arg) do
    printResult = printResult .. tostring(v) .. "\t"
    end
    printResult = printResult .. "\n"
end

有时候我们可能需要几个固定参数加上可变参数

function g (a, b, ...) end
CALL PARAMETERS
g(3) a=3, b=nil, arg={n=0}
g(3, 4) a=3, b=4, arg={n=0}
g(3, 4, 5, 8) a=3, b=4, arg={5, 8; n=2}

如上面所示,Lua 会将前面的实参传给函数的固定参数,后面的实参放在 arg 表中。
举个具体的例子,如果我们只想要 string.find 返回的第二个值。一个典型的方法是
使用哑元(dummy variable,下划线):

local _, x = string.find(s, p)
-- now use `x'
...

还可以利用可变参数声明一个 select 函数:

function select (n, ...)
    return arg[n]
end
print(string.find("hello hello", " hel")) --> 6 9
print(select(1, string.find("hello hello", " hel"))) --> 6
print(select(2, string.find("hello hello", " hel"))) --> 9

有时候需要将函数的可变参数传递给另外的函数调用,可以使用前面我们说过的
unpack(arg)返回 arg 表所有的可变参数,Lua 提供了一个文本格式化的函数 string.format
(类似 C 语言的 sprintf 函数):

function fwrite(fmt, ...)
return io.write(string.format(fmt, unpack(arg)))
end

这个例子将文本格式化操作和写操作组合为一个函数

四、命名参数

Lua 的函数参数是和位置相关的,调用时实参会按顺序依次传给形参。有时候用名
字指定参数是很有用的,比如 rename 函数用来给一个文件重命名,有时候我们我们记不
清命名前后两个参数的顺序了:
– invalid code

rename(old="temp.lua", new="temp1.lua")

上面这段代码是无效的,Lua 可以通过将所有的参数放在一个表中,把表作为函数
的唯一参数来实现上面这段伪代码的功能。因为 Lua 语法支持函数调用时实参可以是表
的构造。

rename{old="temp.lua", new="temp1.lua"}

根据这个想法我们重定义了 rename:

function rename (arg)
    return os.rename(arg.old, arg.new)
end

当函数的参数很多的时候,这种函数参数的传递方式很方便的。例如 GUI 库中创建
窗体的函数有很多参数并且大部分参数是可选的,可以用下面这种方式:

w = Window {
    x = 0, y = 0, width = 300, height = 200,
    title = "Lua", background = "blue",
    border = true
}
function Window (options)
    -- check mandatory 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
    -- everything else is optional
    _Window(options.title,
            options.x or 0,
    -- default value
            options.y or 0,
    -- default value
            options.width, options.height,
            options.background or "white", -- default
            options.border
    -- default is false (nil)
    )
end

五、闭包

案例 1

function test()
    local i=0
    return function() -- 匿名函数
        i= i + 1
        return i
    end
end
c1=test()
c2=test()
print(c1()) -- 1
print(c1()) -- 2//重复调用时每一个调用都会记住上一次调用后的值,就是说i=1了已经
print(c2()) -- 1//闭包不同所以upvalue不同
print(c2()) -- 2
print(c2()) -- 3

闭包:

  • 内部函数调用外部函数的变量
  • 返回内部函数(可以是匿名函数放回)
  • 外部函数+外部函数创建的upvalue+内部函数(闭包函数)
  • 闭包是运行的时候形成的,运行的时候upvalue会单独开辟一块内存来存放
function list_iter(t)
            local i=0
            local n=table.getn(t)
            return function()
                i=i+1
                if i<=n then return t[i] end
            end
        end

案例 2

function DoActive()
		local Hp = 100
		local Mp = 100
		function GetHp()
			Hp= Hp + 1
			return Hp
		end
		return GetHp()
	end

--此时在方法体外去接受DoActive
local A = DoActive()
--此时DoActive会把跟GetHp()相关联的数据形成一个闭包return出来(Hp),而无用的数据(Mp)会被GC掉
--现在A中 有GetHp函数,并且Hp = 101  形成闭包的函数跟数据会在一个空间内储存并挂起,调用时执行
A() -- Hp = 102
A() -- Hp = 103

匿名返回

function DoActive()
		local Hp = 100
		local Mp = 100
		function GetHp()
			Hp= Hp + 1
			return Hp
		end
		return GetHp
	end

local A = DoActive()
A() -- Hp = 102
A() -- Hp = 103

案例 3

function Incremnet(n)
    function show()
        print(n)
    end

    function Add()
        n = n +1
    end
    return show,Add
end
f1,f2 = Incremnet(10)
g1,g2 = Incremnet(20)

f1() -- show 10
f2() -- Add 10 + 1
f1() -- show 11

g1() -- show 20
g2() -- add  20 + 1
g1() -- show 21

六、非全局函数

local 声明

七、尾调用

一个函数调用另外一个函数(并且使用其值)就是尾调用

上一篇:Linux进程间通信详解(五) —— 信号量及函数


下一篇:day31进程_ 数据共享_ 锁 _ 线程池_ 协程