Lua资料之函数(特殊)

◆ 局部函数:
由于全局变量一般会污染全局名字空间,同时也有性能损耗(即查询全局环境表的开销),
因此我们应当尽量使用“局部函数”,其记法是类似的,只是开头加上 local 修饰符:

local function function_name (arc)
  -- body
end

由于函数定义等价于变量赋值,我们也可以把函数名替换为某个 Lua 表的某个字段,例如

function foo.bar(a, b, c)
    -- body ...
end

此时我们是把一个函数类型的值赋给了 foo 表的 bar 字段。换言之,上面的定义等价于

foo.bar = function (a, b, c)
    print(a, b, c)
end

对于此种形式的函数定义,不能再使用 local 修饰符了,因为不存在定义新的局部变量了。

◆ 函数参数问题:
在调用函数的时候,若形参个数和实参个数不同时,Lua 会自动调整实参个数。调整规则:若实参个数大于形参个数,从左向右,多余的实参被忽略;若实参个数小于形参个数,从左向右,没有被实参初始化的形参会被初始化为 nil。

local function fun1(a, b)       --两个形参,多余的实参被忽略掉
   print(a, b)
end
local function fun2(a, b, c, d) --四个形参,没有被实参初始化的形参,用nil初始化
   print(a, b, c, d)
end
local x = 1
local y = 2
local z = 3
fun1(x, y, z)         -- z被函数fun1忽略掉了,参数变成 x, y
fun2(x, y, z)         -- 后面自动加上一个nil,参数变成 x, y, z, nil
-->output
1   2
1   2   3   nil

◆ 变长参数
上面函数的参数都是固定的,其实 Lua 还支持变长参数。若形参为 … , 表示该函数可以接收不同长度的参数。访问参数的时候也要使用 … 。

local function func( ... )                -- 形参为 ... ,表示函数采用变长参数
   local temp = {...}                     -- 访问的时候也要使用 ...
   local ans = table.concat(temp, " ")    -- 使用 table.concat 库函数对数
                                          -- 组内容使用 " " 拼接成字符串。
   print(ans)
end
func(1, 2)        -- 传递了两个参数
func(1, 2, 3, 4)  -- 传递了四个参数
-->output
1 2
1 2 3 4

LuaJIT 2 尚不能 JIT 编译这种变长参数的用法,只能解释执行。所以对性能敏感的代码,应当避免使用此种形式。

◆ 具名参数
Lua 还支持通过名称来指定实参,这时候要把所有的实参组织到一个 table 中,并将这个
table 作为唯一的实参传给函数。

local function change(arg) -- change 函数,改变长方形的长和宽,使其各增长一倍
  arg.width = arg.width * 2
  arg.height = arg.height * 2
  return arg
end
local rectangle = { width = 20, height = 15 }
print("before change:", "width  =", rectangle.width,
                        "height =", rectangle.height)
rectangle = change(rectangle)
print("after  change:", "width  =", rectangle.width,
                        "height =", rectangle.height)
-->output
before change: width = 20  height =  15
after  change: width = 40  height =  30

◆ 按引用传递
当函数参数是 table 类型时,传递进来的是 实际参数的引用,此时在函数内部对该 table 所做的修改,会直接对调用者所传递的实际参数生效,而无需自己返回结果和让调用者进行赋值。 我们把上面改变长方形长和宽的例子修改一下。

function change(arg) --change函数,改变长方形的长和宽,使其各增长一倍
  arg.width = arg.width * 2  --表arg不是表rectangle的拷贝,他们是同一个表
  arg.height = arg.height * 2
end                  -- 没有return语句了
local rectangle = { width = 20, height = 15 }
print("before change:", "width = ", rectangle.width,
                        " height = ", rectangle.height)
change(rectangle)
print("after change:", "width = ", rectangle.width,
                       " height =", rectangle.height)
--> output
before change: width = 20  height = 15
after  change: width = 40  height = 30

在常用基本类型中,除了 table 是按址传递类型外,其它的都是按值传递参数。 用全局变量来代替函数参数的不好编程习惯应该被抵制,良好的编程习惯应该是减少全局变量的使用。

◆ 函数返回值:
当函数返回值的个数和接收返回值的变量的个数不一致时,Lua 也会自动调整参数个数。
调整规则: 若返回值个数大于接收变量的个数,多余的返回值会被忽略掉; 若返回值个数小于参数个数,从左向右,没有被返回值初始化的变量会被初始化为 nil。

function init()             --init 函数 返回两个值 1 和 "lua"
  return 1, "lua"
end
x = init()
print(x)
x, y, z = init()
print(x, y, z)
--output
1
1 lua nil

当一个函数有一个以上返回值,且函数调用不是一个列表表达式的最后一个元素,那么函数调用只会产生一个返回值, 也就是第一个返回值。

local function init()       -- init 函数 返回两个值 1 和 "lua"
    return 1, "lua"
end
local x, y, z = init(), 2   -- init 函数的位置不在最后,此时只返回 1
print(x, y, z)              -->output  1  2  nil
local a, b, c = 2, init()   -- init 函数的位置在最后,此时返回 1 和 "lua"
print(a, b, c)              -->output  2  1  lua

函数调用的实参列表也是一个列表表达式。考虑下面的例子:

local function init()
    return 1, "lua"
end
print(init(), 2)   -->output  1  2
print(2, init())   -->output  2  1  lua

如果你确保只取函数返回值的第一个值,可以使用括号运算符,例如

local function init()
    return 1, "lua"
end
print((init()), 2)   -->output  1  2
print(2, (init()))   -->output  2  1

猜你喜欢

转载自blog.csdn.net/sky6even/article/details/81710685
今日推荐