Lua 函数教程

本教程基于 functions.lua 文件,详细介绍 Lua 编程语言中的函数相关知识。

目录

  1. 基本函数定义和调用
  2. 匿名函数
  3. 闭包
  4. 可变参数函数
  5. 函数返回多个值
  6. 尾调用优化
  7. 函数作为表成员
  8. 词法作用域
  9. 额外内容:函数重载和默认参数

1. 基本函数定义和调用

标准函数定义

在 Lua 中,可以使用 function 关键字定义函数。

1
2
3
4
5
6
7
-- 标准函数定义
function add(a, b)
return a + b
end

local sum = add(10, 20)
print("add(10, 20) =", sum)

函数赋值给变量

函数可以作为值赋给变量,这使得函数可以像其他类型的值一样处理。

1
2
3
4
5
6
7
-- 函数赋值给变量
local multiply = function(a, b)
return a * b
end

local product = multiply(5, 6)
print("multiply(5, 6) =", product)

额外示例:函数作为参数传递

函数可以作为参数传递给其他函数,这是 Lua 函数式编程的重要特性。

1
2
3
4
5
6
7
8
9
10
-- 函数作为参数传递
function apply_operation(a, b, operation)
return operation(a, b)
end

local result1 = apply_operation(10, 5, add)
print("apply_operation(10, 5, add) =", result1)

local result2 = apply_operation(10, 5, function(x, y) return x - y end)
print("apply_operation(10, 5, subtract) =", result2)

2. 匿名函数

匿名函数是没有名称的函数,通常用于简短的操作或作为参数传递给其他函数。

1
2
3
4
5
6
7
8
9
10
11
12
-- 作为参数传递给其他函数
local numbers = {1, 2, 3, 4, 5}

-- 使用匿名函数对表进行排序(降序)
table.sort(numbers, function(a, b)
return a > b
end)

print("Sorted in descending order:")
for _, num in ipairs(numbers) do
print(num)
end

额外示例:使用匿名函数进行表过滤

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
-- 使用匿名函数过滤表中的元素
function filter_table(tbl, condition)
local result = {}
for _, value in ipairs(tbl) do
if condition(value) then
table.insert(result, value)
end
end
return result
end

local numbers = {1, 2, 3, 4, 5, 6, 7, 8, 9, 10}
local even_numbers = filter_table(numbers, function(x) return x % 2 == 0 end)
print("Even numbers:")
for _, num in ipairs(even_numbers) do
print(num)
end

3. 闭包

闭包是一个函数加上它可以访问的外部变量(也称为上值)。闭包可以捕获和保持其创建环境中的变量。

计数器示例

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
-- 闭包函数,返回一个递增计数器
function create_counter(initial)
local count = initial or 0

-- 内部函数可以访问外部函数的局部变量
return function()
count = count + 1
return count
end
end

-- 创建两个计数器实例
local counter1 = create_counter()
local counter2 = create_counter(100)

print("counter1:", counter1())
print("counter1:", counter1())
print("counter2:", counter2())
print("counter1:", counter1())
print("counter2:", counter2())

乘法器示例

1
2
3
4
5
6
7
8
9
10
11
12
-- 另一个闭包示例:生成乘法器
function create_multiplier(factor)
return function(num)
return num * factor
end
end

local double = create_multiplier(2)
local triple = create_multiplier(3)

print("double(5) =", double(5))
print("triple(5) =", triple(5))

额外示例:带有状态的闭包

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
-- 带有状态的闭包:简单的栈实现
function create_stack()
local stack = {}

return {
push = function(value)
table.insert(stack, value)
end,
pop = function()
return table.remove(stack)
end,
size = function()
return #stack
end
}
end

local my_stack = create_stack()
my_stack.push(10)
my_stack.push(20)
my_stack.push(30)
print("Stack size:", my_stack.size())
print("Pop:", my_stack.pop())
print("Stack size after pop:", my_stack.size())

4. 可变参数函数

Lua 支持可变参数函数,即函数可以接受任意数量的参数。使用 ... 表示可变参数。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
-- 使用...表示可变参数
function average(...)
local sum = 0
local count = 0

-- 使用arg获取可变参数(Lua 5.1)或使用...直接迭代(Lua 5.2+)
for _, num in ipairs({...}) do
sum = sum + num
count = count + 1
end

if count == 0 then
return 0
end

return sum / count
end

print("average(1, 2, 3, 4, 5) =", average(1, 2, 3, 4, 5))
print("average(10, 20) =", average(10, 20))
print("average() =", average())

额外示例:处理可变参数的不同方式

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
-- 另一种处理可变参数的方式
function concatenate(...)
local result = ""
for _, str in ipairs({...}) do
result = result .. str
end
return result
end

print("concatenate('Hello', ' ', 'Lua', '!') =", concatenate('Hello', ' ', 'Lua', '!'))

-- 混合固定参数和可变参数
function mixed_args(first, ...)
print("First argument:", first)
print("Remaining arguments:")
for i, arg in ipairs({...}) do
print(i, arg)
end
end

mixed_args("Hello", "World", "Lua", "Programming")

5. 函数返回多个值

Lua 函数可以返回多个值,这是 Lua 的一个重要特性。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
function get_min_max(...) 
local args = {...}
if #args == 0 then
return nil, nil
end

local min_val = args[1]
local max_val = args[1]

for i = 2, #args do
if args[i] < min_val then
min_val = args[i]
end
if args[i] > max_val then
max_val = args[i]
end
end

return min_val, max_val
end

local min, max = get_min_max(5, 2, 9, 1, 7)
print("min and max of {5, 2, 9, 1, 7}:", min, max)

额外示例:返回多个值的应用

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
-- 返回多个值的应用:分解表
function unpack_table(tbl)
return tbl[1], tbl[2], tbl[3]
end

local my_table = {10, 20, 30}
local a, b, c = unpack_table(my_table)
print("Unpacked table:", a, b, c)

-- 返回状态和结果
function divide(a, b)
if b == 0 then
return false, "Division by zero"
end
return true, a / b
end

local success, result = divide(10, 2)
if success then
print("Division result:", result)
else
print("Error:", result)
end

6. 尾调用优化

尾调用是指函数的最后一个操作是调用另一个函数,而不是对调用结果进行任何操作。Lua 会对尾调用进行优化,避免栈溢出。

1
2
3
4
5
6
7
8
9
10
11
-- 尾递归函数:计算阶乘
function factorial_tail(n, acc)
acc = acc or 1
if n <= 1 then
return acc
end
-- 尾调用:函数调用是最后一个操作
return factorial_tail(n - 1, n * acc)
end

print("factorial_tail(5) =", factorial_tail(5))

额外示例:非尾递归 vs 尾递归

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
-- 非尾递归版本(可能导致栈溢出)
function factorial_regular(n)
if n <= 1 then
return 1
end
-- 非尾调用:需要对结果进行乘法操作
return n * factorial_regular(n - 1)
end

print("factorial_regular(5) =", factorial_regular(5))

-- 尾递归版本(不会导致栈溢出)
function factorial_tail(n, acc)
acc = acc or 1
if n <= 1 then
return acc
end
-- 尾调用:函数调用是最后一个操作
return factorial_tail(n - 1, n * acc)
end

print("factorial_tail(5) =", factorial_tail(5))

7. 函数作为表成员

在 Lua 中,函数可以作为表的成员,这是实现面向对象编程的基础。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
local math_operations = {
add = function(a, b) return a + b end,
subtract = function(a, b) return a - b end,
multiply = function(a, b) return a * b end,
divide = function(a, b)
if b == 0 then
return nil, "Division by zero"
end
return a / b
end
}

print("math_operations.add(10, 5) =", math_operations.add(10, 5))
print("math_operations.subtract(10, 5) =", math_operations.subtract(10, 5))
print("math_operations.multiply(10, 5) =", math_operations.multiply(10, 5))

local result, error_msg = math_operations.divide(10, 0)
if result then
print("math_operations.divide(10, 0) =", result)
else
print("Error:", error_msg)
end

额外示例:使用冒号语法定义表方法

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
-- 使用冒号语法定义表方法
local person = {
name = "John",
age = 30,

-- 使用冒号语法定义方法,会自动传入self参数
greet = function(self)
print("Hello, my name is " .. self.name)
end,

-- 另一种使用冒号语法的方式
celebrate_birthday = function(self)
self.age = self.age + 1
print("Happy birthday! I'm now " .. self.age .. " years old.")
end
}

-- 使用冒号调用方法,会自动传入表作为self参数
person:greet()
person:celebrate_birthday()

8. 词法作用域

Lua 使用词法作用域,即变量的作用域由其在代码中的位置决定,而不是由其执行位置决定。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
local outer_var = "outside"

function outer_function()
local inner_var = "inside"

function inner_function()
-- 可以访问外部函数的变量和全局变量
print("inner_var:", inner_var)
print("outer_var:", outer_var)
end

return inner_function
end

local inner = outer_function()
inner()

额外示例:词法作用域的应用

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
-- 词法作用域的应用:创建私有变量
function create_person(name)
local age = 0 -- 私有变量,外部无法直接访问

return {
get_name = function()
return name
end,

get_age = function()
return age
end,

set_age = function(new_age)
if new_age > 0 then
age = new_age
return true
end
return false
end
}
end

local person = create_person("Alice")
print("Name:", person.get_name())
print("Age:", person.get_age())
person.set_age(25)
print("Age after update:", person.get_age())

9. 额外内容:函数重载和默认参数

函数重载

Lua 不直接支持函数重载,但可以通过检查参数类型和数量来模拟函数重载。

1
2
3
4
5
6
7
8
9
10
11
12
13
-- 模拟函数重载
function calculate(a, b)
if type(a) == "number" and type(b) == "number" then
return a + b
elseif type(a) == "string" and type(b) == "string" then
return a .. b
else
return nil, "Invalid arguments"
end
end

print("calculate(1, 2) =", calculate(1, 2))
print("calculate('Hello', ' Lua') =", calculate('Hello', ' Lua'))

默认参数

Lua 不直接支持默认参数,但可以通过检查参数是否为 nil 来实现类似功能。

1
2
3
4
5
6
7
8
9
10
-- 实现默认参数
function greet(name, greeting)
name = name or "Guest"
greeting = greeting or "Hello"
print(greeting .. ", " .. name .. "!")
end

greet("John") -- 使用默认问候语
greet("Jane", "Hi") -- 使用自定义问候语
greet() -- 使用默认名称和问候语

运行示例

要运行 functions.lua 文件,只需在命令行中执行:

1
lua functions.lua

运行结果将显示各个部分的输出,包括函数调用结果、闭包示例、可变参数处理等。

总结

本教程介绍了 Lua 编程语言中的函数相关知识,包括:

  • 基本函数定义和调用
  • 匿名函数
  • 闭包
  • 可变参数函数
  • 函数返回多个值
  • 尾调用优化
  • 函数作为表成员
  • 词法作用域
  • 函数重载和默认参数的模拟实现

通过学习这些知识,您已经掌握了 Lua 函数的核心概念和高级特性,可以编写更加灵活、高效的 Lua 代码。

functions.lua

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
-- Lua函数示例
-- print语句使用英语,注释使用中文

-- 1. 基本函数定义和调用
print("=== Basic Function Definition and Call ===")

-- 标准函数定义
function add(a, b)
return a + b
end

local sum = add(10, 20)
print("add(10, 20) =", sum)

-- 函数赋值给变量
local multiply = function(a, b)
return a * b
end

local product = multiply(5, 6)
print("multiply(5, 6) =", product)

-- 2. 匿名函数
print("\n=== Anonymous Functions ===")

-- 作为参数传递给其他函数
local numbers = {1, 2, 3, 4, 5}

-- 使用匿名函数对表进行排序(降序)
table.sort(numbers, function(a, b)
return a > b
end)

print("Sorted in descending order:")
for _, num in ipairs(numbers) do
print(num)
end

-- 3. 闭包
print("\n=== Closures ===")

-- 闭包函数,返回一个递增计数器
function create_counter(initial)
local count = initial or 0

-- 内部函数可以访问外部函数的局部变量
return function()
count = count + 1
return count
end
end

-- 创建两个计数器实例
local counter1 = create_counter()
local counter2 = create_counter(100)

print("counter1:", counter1())
print("counter1:", counter1())
print("counter2:", counter2())
print("counter1:", counter1())
print("counter2:", counter2())

-- 另一个闭包示例:生成乘法器
function create_multiplier(factor)
return function(num)
return num * factor
end
end

local double = create_multiplier(2)
local triple = create_multiplier(3)

print("double(5) =", double(5))
print("triple(5) =", triple(5))

-- 4. 可变参数函数
print("\n=== Variadic Functions ===")

-- 使用...表示可变参数
function average(...)
local sum = 0
local count = 0

-- 使用arg获取可变参数(Lua 5.1)或使用...直接迭代(Lua 5.2+)
for _, num in ipairs({...}) do
sum = sum + num
count = count + 1
end

if count == 0 then
return 0
end

return sum / count
end

print("average(1, 2, 3, 4, 5) =", average(1, 2, 3, 4, 5))
print("average(10, 20) =", average(10, 20))
print("average() =", average())

-- 5. 函数返回多个值
print("\n=== Functions Returning Multiple Values ===")

function get_min_max(...)
local args = {...}
if #args == 0 then
return nil, nil
end

local min_val = args[1]
local max_val = args[1]

for i = 2, #args do
if args[i] < min_val then
min_val = args[i]
end
if args[i] > max_val then
max_val = args[i]
end
end

return min_val, max_val
end

local min, max = get_min_max(5, 2, 9, 1, 7)
print("min and max of {5, 2, 9, 1, 7}:", min, max)

-- 6. 尾调用优化
print("\n=== Tail Call Optimization ===")

-- 尾递归函数:计算阶乘
function factorial_tail(n, acc)
acc = acc or 1
if n <= 1 then
return acc
end
-- 尾调用:函数调用是最后一个操作
return factorial_tail(n - 1, n * acc)
end

print("factorial_tail(5) =", factorial_tail(5))

-- 7. 函数作为表成员
print("\n=== Functions as Table Members ===")

local math_operations = {
add = function(a, b) return a + b end,
subtract = function(a, b) return a - b end,
multiply = function(a, b) return a * b end,
divide = function(a, b)
if b == 0 then
return nil, "Division by zero"
end
return a / b
end
}

print("math_operations.add(10, 5) =", math_operations.add(10, 5))
print("math_operations.subtract(10, 5) =", math_operations.subtract(10, 5))
print("math_operations.multiply(10, 5) =", math_operations.multiply(10, 5))

local result, error_msg = math_operations.divide(10, 0)
if result then
print("math_operations.divide(10, 0) =", result)
else
print("Error:", error_msg)
end

-- 8. 词法作用域
print("\n=== Lexical Scoping ===")

local outer_var = "outside"

function outer_function()
local inner_var = "inside"

function inner_function()
-- 可以访问外部函数的变量和全局变量
print("inner_var:", inner_var)
print("outer_var:", outer_var)
end

return inner_function
end

local inner = outer_function()
inner()