Menu
CoddyTech

使用 __index 建立关联

本课属于 Coddy Lua 学习旅程的“面向对象编程”单元。第 7 课,共 70 课。

你有一个包含属性和方法的原型表,但怎样才能让新对象真正使用它呢?答案就在 __index 元方法中。

访问表中不存在的键时,Lua 通常会返回 nil。不过,如果表有一个带有 __index 字段的元表,Lua 就会转而在那里查找。将 __index 设置为指向你的原型后,所有缺失的键都会自动在原型中找到:

local Dog = {
    species = "Canis familiaris",
    legs = 4
}

function Dog:bark()
    print("Woof!")
end

-- 创建一个空实例
local myDog = {}

-- 将它关联到原型
setmetatable(myDog, { __index = Dog })

print(myDog.species)  -- 输出:Canis familiaris
myDog:bark()          -- 输出:Woof!

表 myDog 完全为空,但访问 myDog.species 却能正常工作。当 Lua 在 myDog 中找不到 species 时,它会检查元表的 __index,并在 Dog 中找到它。

这是 Lua 面向对象编程的基础。实例可以拥有自己的独特数据,而共享的行为则保存在原型中。在下一课中,你将学习如何将这种模式封装到一个整洁的构造函数中。

challenge icon

挑战

简单

现在,让我们动手使用 __index 元方法!你将创建一个原型并将实例关联到它,这样实例就能访问自己没有直接定义的属性和方法。

你将在两个文件中编写代码:

  • Robot.lua:定义一个 Robot 原型表,其中包含:
    • 一个设为 "RX-100" 的 model 字段
    • 一个设为 100 的 batteryLevel 字段
    • 一个 :status() 方法,用于打印机器人的当前状态
    在文件末尾返回该表。
  • main.lua:引入 Robot 模块,然后创建一个空实例表,并使用 setmetatable 和 __index 将它关联到 Robot 原型。这样,你的空实例就能访问原型中的所有内容。

你会收到一个输入:要赋给机器人实例的名称。

将实例关联到原型后:

  1. 将输入的名称赋给实例的 name 字段(这会成为该实例独有的属性)
  2. 对实例调用 :status() 方法

你的 :status() 方法应按以下确切格式打印:

[name] ([model]) - Battery: [batteryLevel]%

例如,如果输入是 Sparky,输出应为:

Sparky (RX-100) - Battery: 100%

注意,实例有自己的 name,但会通过 __index 链接从原型访问 model 和 batteryLevel。

亲手试试

-- 读取输入
local name = io.read()

-- 加载 Robot 模块
local Robot = require('Robot')

-- TODO: 创建一个空的实例表

-- TODO: 使用 setmetatable 和 __index 将实例关联到 Robot 原型

-- TODO: 将输入的名称赋值给你的实例的 name 字段

-- TODO: 调用你的实例的 :status() 方法
quiz icon自我测试

这节课包含一个小测验。开始学习即可作答,并记录你的进度。

面向对象编程中的所有课

自己练习: Lua 在线编译器