第6章 - 函数
嗨,朋友!我是长安。
函数是 Lua 中最强大的特性之一。Lua 的函数是一等公民(first-class),可以赋值给变量、作为参数传递、作为返回值——这些在 Java 8 之前是做不到的。
🚀 基本函数定义
Lua 写法
-- 定义一个函数
local function greet(name)
print("你好," .. name .. "!")
end
-- 调用函数
greet("长安") -- 你好,长安!
Java 写法
public void greet(String name) {
System.out.println("你好," + name + "!");
}
greet("长安"); // 你好,长安!
语法对比
| 特性 | Java | Lua |
|---|---|---|
| 关键字 | 无(用返回类型) | function |
| 参数类型 | 必须声明 | 不需要 |
| 返回类型 | 必须声明 | 不需要 |
| 结束标记 | } | end |
| 访问修饰符 | public/private 等 | 无(用 local 控制作用域) |
📤 返回值
单返回值
local function add(a, b)
return a + b
end
local result = add(3, 5)
print(result) -- 8
🌟 多返回值(Java 做不到!)
-- Lua 函数可以返回多个值!
local function getPersonInfo()
return "长安", 25, "Java开发"
end
local name, age, job = getPersonInfo()
print(name) -- 长安
print(age) -- 25
print(job) -- Java开发
-- 只取部分返回值
local name2 = getPersonInfo() -- 只取第一个
print(name2) -- 长安
-- 用 _ 忽略不需要的值
local _, age2 = getPersonInfo() -- 忽略第一个,取第二个
print(age2) -- 25
// Java 不能直接返回多个值,通常用对象或数组
public class PersonInfo {
String name;
int age;
String job;
}
// 或者用 Map
public Map<String, Object> getPersonInfo() {
Map<String, Object> map = new HashMap<>();
map.put("name", "长安");
map.put("age", 25);
map.put("job", "Java开发");
return map;
}
多返回值
多返回值是 Lua 的一大特色!Java 需要用对象、数组、或 Pair/Tuple 来实现,而 Lua 直接支持。
📋 可变参数
-- 可变参数用 ...
local function sum(...)
local args = {...} -- 把可变参数收集到表中
local total = 0
for _, v in ipairs(args) do
total = total + v
end
return total
end
print(sum(1, 2, 3)) -- 6
print(sum(1, 2, 3, 4, 5)) -- 15
// Java 的可变参数
public int sum(int... nums) {
int total = 0;
for (int n : nums) {
total += n;
}
return total;
}
🎭 函数是一等公民
在 Lua 中,函数就是一个值,可以像普通变量一样使用:
-- 函数赋值给变量
local myPrint = print
myPrint("Hello!") -- Hello!
-- 匿名函数(类似 Java 的 Lambda)
local add = function(a, b)
return a + b
end
print(add(3, 5)) -- 8
-- 函数作为参数传递
local function applyOperation(a, b, operation)
return operation(a, b)
end
print(applyOperation(10, 3, function(a, b) return a + b end)) -- 13
print(applyOperation(10, 3, function(a, b) return a * b end)) -- 30
// Java 8+ Lambda 等价写法
BiFunction<Integer, Integer, Integer> add = (a, b) -> a + b;
System.out.println(add.apply(3, 5)); // 8
public int applyOperation(int a, int b, BiFunction<Integer, Integer, Integer> op) {
return op.apply(a, b);
}
applyOperation(10, 3, (a, b) -> a + b); // 13
🔒 闭包(Closure)
闭包是函数 + 它引用的外部变量:
local function createCounter()
local count = 0 -- 外部变量(被闭包捕获)
return function() -- 返回一个闭包
count = count + 1
return count
end
end
local counter = createCounter()
print(counter()) -- 1
print(counter()) -- 2
print(counter()) -- 3
-- 每个闭包有自己的独立环境
local counter2 = createCounter()
print(counter2()) -- 1(独立计数)
// Java 也有闭包(通过 Lambda 实现)
public Supplier<Integer> createCounter() {
final int[] count = {0}; // Java Lambda 要求"事实上的 final"
return () -> ++count[0];
}
Supplier<Integer> counter = createCounter();
System.out.println(counter.get()); // 1
System.out.println(counter.get()); // 2
闭包的实用场景
闭包在 Lua 中非常常用,常见的应用:
- 封装私有状态 — 类似 Java 的私有属性
- 回调函数 — 保存上下文信息
- 迭代器 — 自定义迭代行为
- 缓存/记忆化 — 缓存函数计算结果
📦 函数的两种定义方式
-- 方式一:标准写法
local function foo(x)
return x * 2
end
-- 方式二:变量赋值写法(完全等价)
local foo = function(x)
return x * 2
end
-- 方式一其实是方式二的语法糖
注意递归
如果函数需要递归调用自己,推荐用方式一:
-- ✅ 正确:标准写法支持递归
local function factorial(n)
if n <= 1 then return 1 end
return n * factorial(n - 1)
end
-- ❌ 可能出错:变量赋值写法
local factorial = function(n)
if n <= 1 then return 1 end
return n * factorial(n - 1) -- 这里的 factorial 可能还是 nil!
end
🔧 常用的内置函数
-- 类型相关
print(type(42)) -- "number"
print(tostring(42)) -- "42"
print(tonumber("42")) -- 42
-- 数学相关
print(math.max(1, 5, 3)) -- 5
print(math.min(1, 5, 3)) -- 1
print(math.floor(3.7)) -- 3
print(math.ceil(3.2)) -- 4
print(math.random(1, 100)) -- 随机数
-- 表(数组)相关
local t = {3, 1, 4, 1, 5}
table.sort(t)
table.insert(t, 9) -- 在末尾插入
table.remove(t, 1) -- 删除第一个元素
📝 小结
- Lua 函数用
function ... end定义,不需要声明参数类型和返回类型 - 函数可以返回多个值,这是 Java 做不到的
- 函数是一等公民,可以赋值、传参、返回
- 闭包是 Lua 的强大特性,可以封装私有状态
- 推荐使用
local function定义函数
➡️ 下一步
函数掌握了!下一章我们来学习 Lua 最核心的数据结构——Table(表),它能当数组、字典、甚至对象用!
💪 练习题
- 写一个函数,接收两个数字,返回它们的和与差(两个返回值)。
- 写一个闭包,实现一个计数器,每次调用返回递增的值。
- 写一个函数,接收一个函数作为参数,对数组中的每个元素执行该函数。
local function foo()和local foo = function()有什么区别?
答案提示
local function calc(a, b) return a + b, a - b end- 参考本章的
createCounter示例 local function map(t, fn) for i, v in ipairs(t) do t[i] = fn(v) end end- 前者支持递归调用自身,后者在递归时可能引用到 nil
