0Pricing
Lua Academy · 课时

定义和调用函数

学习函数声明语法、调用约定,以及局部函数与全局函数的区别。

定义和调用函数 是 CoddyKit 上的免费 Lua Academy 课时。 这是第 1 节课,共 4 节。 你可以在下方免费阅读本课时的完整内容 — 然后在浏览器中使用内置代码编辑器和全天候 AI 导师进行实践。 这是 Lua Academy 学习路径的一部分,你的进度在网页和 CoddyKit 应用中同步。 Lua Academy 课程共包含 4 节课。

函数语法

Lua 使用 function 关键字定义函数。函数体是一个以 end 结束的代码块。函数可以是全局的,也可以是局部的。调用函数时,在函数名后添加带参数的括号。如果省略参数,缺少的参数会接收 nil。

function sayHello(name)
  print("Hello, " .. (name or "World") .. "!")
end

sayHello("Lua")   -- Hello, Lua!
sayHello()        -- Hello, World!

local function add(a, b)
  return a + b
end
print(add(3, 4))  -- 7

返回值

函数使用 return 返回值。与大多数语言不同,Lua 函数可以返回多个值。如果没有显式返回,函数不会返回任何值(零个值)。当函数调用不是列表中的最后一个表达式时,多余的返回值会被丢弃。

local function minMax(t)
  local lo, hi = t[1], t[1]
  for i = 2, #t do
    if t[i] < lo then lo = t[i] end
    if t[i] > hi then hi = t[i] end
  end
  return lo, hi
end

local lo, hi = minMax({5,2,8,1,9})
print(lo, hi)  -- 1  9

函数作为值

在 Lua 中,函数是一级值。您可以将函数存储在变量中,将其作为参数传递给其他函数,也可以返回函数。这使回调、高阶函数和函数式编程模式成为可能。

local ops = {
  add = function(a, b) return a + b end,
  sub = function(a, b) return a - b end,
  mul = function(a, b) return a * b end,
}

local function apply(op, a, b)
  return op(a, b)
end

print(apply(ops.add, 10, 3))  -- 13
print(apply(ops.mul, 4, 5))   -- 20

局部函数与全局函数

对于模块私有的辅助函数,请使用 local function。全局函数会污染全局命名空间,并且可以从任何位置访问,因而可能造成命名冲突。在大多数情况下,优先使用局部函数,只通过模块表公开所需的内容。

-- Bad: pollutes global namespace
function helper() end

-- Good: module-local
local function helper()
  return "I am local"
end

-- Module export pattern
local M = {}
function M.publicFunc()
  return helper()  -- can call local
end
return M

使用冒号语法定义方法

Lua 为在表上定义和调用方法提供了语法糖。obj:method(arg) 等价于 obj.method(obj, arg)。冒号形式会隐式地将该表作为第一个参数传入,这个参数通常命名为 self。

local Dog = {}
Dog.__index = Dog

function Dog.new(name)
  return setmetatable({name=name}, Dog)
end

function Dog:speak()
  print(self.name .. " says: Woof!")
end

local d = Dog.new("Rex")
d:speak()   -- Rex says: Woof!

可选参数模式

Lua 没有内置的可选参数,但可以通过检查 nil 来模拟。对于包含许多可选参数的函数,可以传入一个选项表——这比使用很长的参数列表更清晰。

local function createUser(name, opts)
  opts = opts or {}
  return {
    name = name,
    role = opts.role or "user",
    active = opts.active ~= false,
    score = opts.score or 0,
  }
end

local u = createUser("Alice", {role="admin", score=100})
print(u.name, u.role, u.score)

尾调用

尾调用是处于尾部位置的函数调用(返回前执行的最后一个操作)。Lua 会执行尾调用优化:正确的尾调用不会占用额外的栈空间。当递归调用处于尾部位置时,这使得深度递归不会发生栈溢出。

local function factorial(n, acc)
  acc = acc or 1
  if n <= 1 then return acc end
  return factorial(n - 1, n * acc)  -- tail call!
end

print(factorial(10))  -- 3628800
-- Can handle very large n without stack overflow

立即调用函数

您可以定义函数并立即调用它:(function() ... end)()。这对于创建局部作用域、恰好执行一次初始化代码,或避免临时变量污染外部作用域非常有用。

local result = (function()
  local temp = 100
  local adjusted = temp * 1.5
  return math.floor(adjusted)
end)()

print(result)   -- 150
-- temp and adjusted not visible here

将函数存储在表中

将函数存储在表中是符合 Lua 惯用方式的模块设计。表充当命名空间。您可以将函数赋给表字段,或者使用以表名为对象的点号/冒号表示法来定义函数。

local math2 = {}

function math2.clamp(val, lo, hi)
  return math.max(lo, math.min(hi, val))
end

function math2.lerp(a, b, t)
  return a + (b - a) * t
end

print(math2.clamp(150, 0, 100))  -- 100
print(math2.lerp(0, 10, 0.5))   -- 5.0

作为回调的闭包

高阶函数会接受回调。在 Lua 中,回调就是函数值。闭包尤其适合作为回调,因为它们可以捕获调用上下文,而不需要通过高阶函数传递额外参数。

local function forEach(t, fn)
  for i, v in ipairs(t) do
    fn(v, i)
  end
end

local sum = 0
forEach({10, 20, 30}, function(v)
  sum = sum + v
end)
print(sum)   -- 60

forEach({"a","b","c"}, function(v, i)
  print(i, v)
end)

快速检查

以下代码的输出是什么:local function f() return 1, 2, 3 end; local a, b = f()?

回顾:函数

要点:

  • 使用 local function,避免污染全局环境
  • 函数是一等值:可以存储在变量和表中,也可以作为参数传递
  • 冒号语法会隐式传递 self
  • 使用 opts or {} 模拟可选参数
  • 尾调用可以避免深度递归导致的栈溢出
  • 立即调用的函数会创建隔离的作用域

常见问题解答

「定义和调用函数」课时是免费的吗?

是的 — 「定义和调用函数」的完整文本可在网页上免费阅读。要进行交互式练习(内置代码编辑器和全天候 AI 导师)并解锁 Lua Academy 课程的其余内容,请升级到 CoddyKit PRO。 Lua Academy 课程共包含 4 节课。

「定义和调用函数」这节课中我会学到什么?

学习函数声明语法、调用约定,以及局部函数与全局函数的区别。 你通过在浏览器中直接运行的动手代码来练习 Lua Academy,全天候 AI 导师会在你学习这节课的过程中回答你的问题。

学习 Lua Academy 需要有经验吗?

无需任何先前经验。CoddyKit 上的 Lua Academy 课程适合初学者到高级学习者,你可以从这里开始或从头开始,按照自己的节奏学习。 这是第 1 节课,共 4 节。

「定义和调用函数」课时需要多长时间?

大多数 CoddyKit 课程大约需要 5–10 分钟。每节课都很精短且互动,所以你能稳步进步,并在网页和应用中从离开的地方继续。

我能在这节 Lua Academy 课中编写并运行代码吗?

能。每节 Lua Academy 课都包含内置代码编辑器,你可以在浏览器中直接编写并运行真实代码,并获得即时 AI 反馈 — 无需本地设置。

此课程中的所有课时

  1. 定义和调用函数
  2. 多个返回值
  3. 可变参数和 ... 运算符
  4. Lua 中的递归
← 返回 Lua Academy