Lua 函数使用的完整指南

在 Lua 中,函数是一等公民(First-Class Citizen),这意味着函数可以像其他值一样被赋值、传递和操作。以下是 Lua 函数定义的完整指南,涵盖基础语法、高级特性、设计模式及性能优化。



一、基础语法

1. 函数声明

-- 基础语法
function add(a, b)
    return a + b
end

-- 调用
print(add(3, 5))  -- 输出 8

2. 匿名函数

-- 无名称的函数(常用于回调)
local function factorial(n)
    return n == 0 and 1 or n * factorial(n-1)
end

-- 将函数赋值给变量
local square = function(x) return x * x end
print(square(4))  -- 输出 16

二、核心特性

1. 多返回值

function divide_and_remainder(a, b)
    return math.floor(a / b), a % b
end

local quotient, remainder = divide_and_remainder(10, 3)
print(quotient, remainder)  -- 输出 3 1

2. 变参函数(Variadic Function)

-- 使用 ... 接收任意数量参数
function sum(...)
    local total = 0
    for _, v in ipairs({
    
    ...}) do
        total = total + v
    end
    return total
end

print(sum(1,2,3,4))  -- 输出 10

3. 函数作为返回值

function make_adder(x)
    return function(y)
        return x + y
    end
end

local add5 = make_adder(5)
print(add5(3))  -- 输出 8

三、进阶特性

1. 闭包(Closure)

闭包是函数与其词法环境的组合,可捕获外部变量:

function counter()
    local count = 0
    return function()
        count = count + 1
        return count
    end
end

local c = counter()
print(c())  -- 1
print(c())  -- 2

2. 尾调用优化(Tail Call Optimization)

尾调用不会增加调用栈深度,防止栈溢出:

function factorial(n, acc)
    acc = acc or 1
    if n == 0 then return acc end
    return factorial(n-1, n*acc)  -- 尾递归优化
end

print(factorial(5))  -- 输出 120

3. 高阶函数(Higher-Order Function)

函数作为参数或返回值:

-- map 函数
function map(t, fn)
    local result = {
    
    }
    for _, v in ipairs(t) do
        table.insert(result, fn(v))
    end
    return result
end

local numbers = {
    
    1,2,3,4}
local squares = map(numbers, function(x) return x*x end)
print(table.unpack(squares))  -- 输出 1 4 9 16

四、函数属性与元编程

1. 函数属性

function greet(name)
    return "Hello, " .. name
end

greet.__call = function(self, ...)
    return self.name .. ", " .. ...
end

setmetatable(greet, {
    
     __call = function(f, name) return "Hi, "..name end })

print(greet("Alice"))  -- 输出 Hi, Alice

2. 元表与函数钩子

-- 统计函数调用次数
local call_counts = {
    
    }
local function hook(func)
    return function(...)
        call_counts[func] = (call_counts[func] or 0) + 1
        return func(...)
    end
end

local function add(a, b)
    return a + b
end

add = hook(add)
add(1,2)
add(3,4)
print(call_counts[add])  -- 输出 2

五、性能优化指南

1. 避免闭包滥用

-- 低效写法:频繁创建闭包
for i = 1, 1000 do
    local function fn() return i end  -- 每次循环都创建新闭包
end

-- 优化写法:使用局部变量捕获
for i = 1, 1000 do
    local i_local = i
    local function fn() return i_local end
end

2. 内联小函数

-- 频繁调用的简单函数可内联
-- 优化前
local function square(x) return x*x end
for i = 1, 1e6 do
    square(i)
end

-- 优化后
for i = 1, 1e6 do
    local x = i*i  -- 直接展开计算
end

3. 使用局部函数

-- 全局函数查找较慢
function global_fn() end

-- 优化:优先使用局部函数
local local_fn = function() end

六、设计模式与最佳实践

1. 策略模式

local strategies = {
    
    
    add = function(a,b) return a+b end,
    multiply = function(a,b) return a*b end
}

function calculate(operation, a, b)
    return (strategies[operation] or strategies.add)(a, b)
end

print(calculate("multiply", 3,4))  -- 输出 12

2. 工厂模式

local function create_user(name, age)
    return {
    
    
        name = name,
        age = age,
        greet = function(self)
            print("I'm", self.name)
        end
    }
end

local alice = create_user("Alice", 30)
alice:greet()  -- 输出 I'm Alice

3. 观察者模式

local function observable()
    local listeners = {
    
    }
    return setmetatable({
    
    }, {
    
    
        __newindex = function(t,k,v)
            rawset(t, k, v)
            for _, listener in ipairs(listeners) do
                listener(k, v)
            end
        end,
        add_listener = function(t, listener)
            table.insert(listeners, listener)
        end
    })
end

local obj = observable()
obj:add_listener(function(key, value)
    print("Property changed:", key, value)
end)
obj.x = 10  -- 触发监听器输出

七、调试与元信息

1. 获取函数信息

function example(a, b)
    return a + b
end

print(debug.getinfo(example).name)  -- 输出 "example"
print(debug.getupvalue(example, 1))  -- 查看闭包的上层变量(若有)

2. 函数重载(模拟)

local function overloaded(fn)
    local cache = {
    
    }
    return function(...)
        local key = table.concat({
    
    ...}, "|")
        if not cache[key] then
            cache[key] = fn(...)
        end
        return cache[key]
    end
end

local function process(a, b)
    return a + b
end

local process_overloaded = overloaded(process)
print(process_overloaded(1,2))  -- 计算并缓存
print(process_overloaded(1,2))  -- 直接返回缓存结果

八、常见问题与解决方案

问题1:函数参数过多时的处理

-- 使用表传递可选参数
function config(options)
    local defaults = {
    
    width=800, height=600}
    for k, v in pairs(options) do
        defaults[k] = v
    end
    return defaults
end

local cfg = config({
    
    height=400})
print(cfg.width, cfg.height)  -- 输出 800 400

问题2:递归深度过大导致栈溢出

-- 尾递归优化版本
function fibonacci(n, a, b)
    a = a or 0
    b = b or 1
    if n == 0 then return a end
    if n == 1 then return b end
    return fibonacci(n-1, b, a+b)
end

print(fibonacci(1000))  -- 不会导致栈溢出

通过掌握这些函数特性与模式,你可以编写出高效、灵活的 Lua 代码。对于复杂场景,建议结合元编程和设计模式,同时注意性能优化细节。