mthoutai

  博客园  :: 首页  :: 新随笔  :: 联系 :: 订阅 订阅  :: 管理

学习到Lua的函数。认为有必要记下来。

參考教程:Programming in Lua

函数能够以表达式陈述语句出现,例如以下所看到的:

  print(8*9, 9/8)
  a = math.sin(3) + math.cos(10)

书写函数时有个小规则,假设函数仅仅有一个參数。或者是一串字符。或者是一个表结构时。括号能够省略:

   print "Hello World" <--> print("Hello World")
   dofile 'a.lua' <--> dofile ('a.lua')
   f{x=10, y=20} <--> f({x=10, y=20})
   type{} <--> type({})

对于Lua的面向对象,有一个特殊的语法来使用函数,就是使用冒号:

o:foo(x)

lua函数的一般写法:

    function fun_name(<parameters>)
        <body>
    end

举个样例:

    -- add the elements of sequence 'a'
    function add (a)
        local sum = 0
        for i = 1, #a do
            sum = sum + a[i]
        end
        return sum
    end

调用Lua函数时,传递的參数和实际參数数目能够不一样,Lua会自己主动调整參数匹配。

假设传递的參数比实际參数多了,那么多于的会被舍弃。少于的会得到nil值。

比方有个函数有以下几种情况:

    f(3) --> 3 nil
    f(3, 4) --> 3 4
    f(3, 4, 5) --> 3 4 (5 is discarded)

这个特性能够被用来设置參数的默认值:

    function incCount (n)
        n = n or 1
        count = count + n
    end

lua的函数能够有多个返回值

比方lua库函数string.find:

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

lua函数的返回值数目也能够依据函数实际调用情况进行调整

比方以下三个函数:

function foo0 () end -- returns no results
function foo1 () return "a" end -- returns 1 result
function foo2 () return "a", "b" end -- returns 2 results

多重赋值时。要依据函数的调用位置来决定返回值的数目。函数调用在表达式末尾。则依据实际情况返回结果值。

x,y = foo2() -- x="a", y="b"
x = foo2() -- x="a", "b" is discarded
x,y,z = 10,foo2() -- x=10, y="a", z="b"

无返回值或返回值数目小于多重赋值数目,则多于的值为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
x,y = foo0(), 20, 30 -- x=nil, y=20, 30 is discarded

当一个函数调用是另外一个函数的最后一个參数。那么第一个函数返回的全部结果都是还有一个函数的參数。

print(foo0()) -->
print(foo1()) --> a
print(foo2()) --> a b
print(foo2(), 1) --> a 1
print(foo2() .. "x") --> ax (see next)

表构造能收集函数的全部返回值。不须要做出调整。

t = {foo0()} -- t = {} (an empty table)
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)) -- (no results)
print(foo(3)) -- (no results)

当然也能够通过一个括号来仅仅返回一个结果值:

print((foo0())) --> nil
print((foo1())) --> a
print((foo2())) --> a

有个特别的函数table.unpack就是有多个返回值:

print(table.unpack{10,20,30}) --> 10 20 30
a,b = table.unpack{10,20,30} -- a=10, b=20, 30 is discarded

unpack能帮助你实现一个调用含有随意參数的随意函数机制,说白了。能实现函数的动态调用。还是看样例。

f(table.unpack(a))

这个函数将a中的全部值作为f函数的參数。
以下看这个函数调用:

print(string.find("hello", "ll"))

你能够动态的进行改写:

f = string.find
a = {"hello", "ll"}
print(f(table.unpack(a)))

通常来说,unpack使用长度运算符来确定元素的返回数目,所以它是针对适当的序列来说的。

可是假设须要。能够加以限制:

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

參数可变的函数

lua的函数能够拥有可变參数,也就是參数数目可变。print就是这样一个函数。

以下是用Lua函数实现的可变參数函数样例:

function add (...)
    local s = 0
    for i, v in ipairs{...} do
    s = s + v
    end
    return s
end
print(add(3, 4, 10, 25, 12)) --> 54

…这三点就是表明一个函数有可变參数。…叫做參数变量表达式。表现相似一个返回全部结果值的函数。

能够模仿函数參数传递机制:

function foo (a, b, c)

变为:

function foo (...)
    local a, b, c = ...

再看:
function id (…) return … end

function foo1 (...)
    print("calling foo:", ...)
    return foo(...)
end

上面这个机制能够用来进行跟踪调试。

以下是另外一个实用的样例。结合string.format与io.write函数:

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

注意上面的三点在fmt之后。

由于Lua函数中可变參数这部分之前能够是參数数目确定的部分。

CALL                        PARAMETERS
fwrite()                    fmt = nil, no extra arguments
fwrite("a")                 fmt = "a", no extras
fwrite("%d%d", 4, 5)        fmt = "%d%d", extras = 4 and 5

有极少数情况下,可变參数中可能有nil值,这时候{…}就不适用了。

这样的情况下。就要用table.pack函数,这个函数接收随意数目參数然后返回一个新的表。可是这个表有个额外的n区域,表示元素数目。
以下的样例測试是否有參数为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

在可变參数中不会有nil值的情况下{…}比table.pack(…)速度快多了。

命名參数

Lua中函数參数传递是基于位置的。可是。也能够通过名字来定义參数,这在某些时候非常实用,比方os.rename函数,对一个文件重命名。

通常,我们不知道哪个文件名称在前。

这是,通过名字就非常实用了:

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

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

这样的风格的函数传递在函数有非常多參数且它们当中大部分都是可选项时是非常实用的。比方GUI编程中。

posted on 2017-07-04 21:34  mthoutai  阅读(386)  评论(0编辑  收藏  举报