• 友链

  • 首页

  • 文章归档
h u a n b l o g
h u a n b l o g

欢

HI,Friend

04月
19
Lua

Lua函数

发表于 2022-04-19 • 字数统计 5095 • 被 1,477 人看爆

前言

Lua提供了一种特殊的函数调用语法,即冒号.如:o:foo(x)的表达式意为调用对象o的foo方法

调用函数时使用的参数个数可以与定义函数时使用的参数个数不一致。Lua语言会通过抛弃多余参数和将不足的参数设为nil的方式来调整参数的个数。

function f(a, b)
    print(a, b)
end

f()         -->nil  nil
f(3)        -->3    nil
f(3, 4)     -->3    4
f(3, 4, 5)  -->3    4       5被舍去   

多返回值

Lua中允许一个函数返回多个结果

多个变量定义也是可以这样

a, b = 3, 4
print(a, b)     -->3    4

如:函数string.find用于在字符串中定位模式。返回两个索引值:所匹配模式在字符串中起始字符和结尾字符的索引

s, e = string.find("hello Lua users", "Lua")
print(s, e)     -->7    9

function maximum (a)
    local mi= 1         --最大值的索引
    local m = a[mi]     --最大值
    for i = 1, #a do
        if a[i] > m then
            mi = i; m = a[i]
        end
    end
    return m, mi        --返回最大值及其索引
end

print(maximum({8,10,23,12,5}))  -->23   3

Lua语言根据函数的被调用情况调整返回值的数量。当函数被作为一条单独语句调用时,其所有返回值都会被丢弃;当函数被作为表达式(例如,加法的操作数)调用时,将只保留函数的第一个返回值。只有当函数调用是一系列表达式中的最后一个表达式(或是唯一一个表达式)时,其所有的返回值才能被获取到。

"一系列表达式":多重赋值、函数调用时传入实参列表、表构造器和return语句

return语句

function foo0 () end                    --不返回结果
function foo1 () return "a" end         --返回1个结果
function foo2 () return "a","b" end    --返回2个结果

多重赋值

在多重赋值中,如果一个函数调用是一系列表达式中的最后(或者是唯一)一个表达式,则该函数调用将产生尽可能多的返回值以匹配待赋值变量:

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=nil
x, y = foo1()       --x="a", y=nil
x, y, z = foo2()    --x="a", y="b", z=nil

请注意,只有当函数调用是一系列表达式中的最后(或者是唯一)一个表达式时才能返回多值结果,否则只能返回一个结果:

x, y = foo2(),20    --x="a", y=20   ('b'被丢弃)
x, y =foo0(),20,30  --x=nil, y=20   (30被丢弃)

函数调用时传入实参列表
当一个函数调用是另一个函数调用的最后一个(或者是唯一)实参时,第一个函数的所有返回值都会被作为实参传给第二个函数。例如函数print。由于函数print能够接收可变数量的参数,所以print(g())会打印出g返回的所有结果。

print(foo0())           -->(没有结果)
print(foo1())           -->a
print(foo2())           -->a b
print(foo2(),1)        -->a 1      当在表达式中调用foo2时,Lua语言会把其返回值的个数调整为1
print(foo2() .. "x")--> -->ax

当我们调用f(g())时,如果f的参数是固定的,那么Lua语言会把g返回值的个数调整成与f的参数个数一致。

表构造器
表构造器会完整地接收函数调用的所有返回值,而不会调整返回值的个数:

t = {foo0()}        --t = {}(一个空表)
t = {foo1()}        --t = {"a"}
t = {foo2()}        --t = {"a","b"}

不过,这种行为只有当函数调用是表达式列表中的最后一个时才有效,在其他位置上的函数调用总是只返回一个结果:

t = {foo0(),foo2(),4}      --t[1] = nil, t[2] = "a", t[3] =4

最后,形如return f()的语句会返回f返回的所有结果:

function foo (i)
    if i == 0 then return foo0()
    elseif i == 1 then return foo1()
    elseif i == 2 then return foo2()
    end
end

print(foo(1))       -->a
print(foo(2))       -->a  b
print(foo(0))       --(无结果)
print(foo(3))       --(无结果)

--直接调用函数,则只返回一个
print((foo0()))     -->nil
print((foo1()))     -->a
print((foo2()))     -->a

可变长参数函数

即可以支持数量可变的参数,使用...表示参数可变

function add (...)
    local s = 0
    for _, v in ipairs{...} do
        s = S + v
    end
    return s
end

print( add(3,4,10,25,12))       -->54

使用格式化输出函数string.format和输出文本函数io.write,可以将两个函数合并为一个具有可变参数的函数

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

可用函数table.pack来检测参数中是否有nil

function nonils (...)
    local arg = table.pack( .. .)
    for i = 1, arg.n do
        if arg[i] == nil then return false end
    end
    return true
end

print(nonils(2,3,nil))     --> false
print(nonils(2,3))         --> true
print(nonils())            --> true
print(nonils(nil))         --> false

  使用函数select,来遍历可变参数
  函数select总是具有一个固定的参数selector,以及数量可变的参数。如果selector是数值n,那么函数 select则返回第n个参数后的所有参数;否则,selector应该是字符串"#",以便函数select返回额外参数的总数。

print(select(1, "a", "b", "c"))     --> a b c
print(select(2, "a", "b", "c"))     --> b c
print(select(3,"a", "b", "c"))     --> c
print(select("#", "a", "b", "c"))   --> 3

通常,我们在需要把返回值个数调整为1的地方使用函数select,因此可以把select(n,...)认为是返回第n个额外参数的表达式。

function add (...)
    local s = 0
    for i = 1, select("#",...) do
        s = s + select(i, ...)
    end
    return s
end

对于参数较少的情况,使用add 更快

函数table.unpack

多重返回值还涉及一个特殊的函数table.unpack。该函数的参数是一个数组,返回值为数组内的所有元素:

print(table.unpack{10,20,30})       -->10   20  30
a, b = table.unpack{10,20,30}       -- a=10, b=20,30被丢弃

与table.pack功能相反。pack把参数列表转换成Lua语言中一个真实的列表(一个表),而unpack 则把Lua语言中的真实的列表(一个表)转换成一组返回值,进而可以作为另一个函数的参数被使用。

unpack函数的重要用途之一体现在泛型调用机制中。

泛型调用机制允许我们动态地调用具有任意参数的任意函数。

f(table.unpack(a))      --unpack会返回a中所有的元素,而这些元素又被用作f的参数。

函数table.unpack使用长度操作符获取返回值的个数,因而该函数只能用于序列。不过,如果有需要,也可以显式地限制返回元素的范围:


print(table.unpack({" Sun" ,"Mon" ,"Tue" ,"Wed"},2,3))       -->Mon Tue

尾调用

尾调用是被当作函数调用使用的跳转。

  当一个函数的最后一个动作是调用另一个函数而没有再进行其他工作时,就形成了尾调用。

--当函数f调用完函数g之后,f不再需要进行其他的工作。
function f(x) x = x + 1; return g(x) end

尾调用时不使用任何额外的栈空间,不会产生栈溢出。我们就将这种实现称为尾调用消除。

判断是否是尾调用,函数调用后还进行其它工作,就不是尾调用

--不是      当调用完g后,f在返回前还不得不丢弃g返回的所有结果
function f (x)  g(x)    end
return g(x) + 1     --不是  必须进行加法
return x or g(x)    --不是  必须把返回值限制为1个
return (g(x))       --不是  必须把返回值限制为1个

在 Lua语言中,只有形如return func(args)的调用才是尾调用。

--是尾调用
return x[i].foo(x[j] + a*b, i + j)
分享到:
Lua输入和输出
Lua表
  • 文章目录
  • 站点概览
欢

网红 欢

你能抓到我么?

Email RSS
看爆 Top5
  • mac系统版本与Xcode版本有冲突 4,080次看爆
  • JAVA_HOME环境配置问题 3,731次看爆
  • AssetBundle使用 3,499次看爆
  • VSCode配置C++开发环境 3,257次看爆
  • Lua反射 3,133次看爆

Copyright © 2025 欢 粤ICP备2020105803号-1

由 Halo 强力驱动 · Theme by Sagiri · 站点地图