使用 __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 面向对象编程的基础。实例可以拥有自己的独特数据,而共享的行为则保存在原型中。在下一课中,你将学习如何将这种模式封装到一个整洁的构造函数中。
挑战
简单现在,让我们动手使用 __index 元方法!你将创建一个原型并将实例关联到它,这样实例就能访问自己没有直接定义的属性和方法。
你将在两个文件中编写代码:
Robot.lua:定义一个Robot原型表,其中包含:- 一个设为
"RX-100"的model字段 - 一个设为
100的batteryLevel字段 - 一个
:status()方法,用于打印机器人的当前状态
- 一个设为
main.lua:引入 Robot 模块,然后创建一个空实例表,并使用setmetatable和__index将它关联到 Robot 原型。这样,你的空实例就能访问原型中的所有内容。
你会收到一个输入:要赋给机器人实例的名称。
将实例关联到原型后:
- 将输入的名称赋给实例的
name字段(这会成为该实例独有的属性) - 对实例调用
: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() 方法
这节课包含一个小测验。开始学习即可作答,并记录你的进度。
面向对象编程中的所有课
自己练习: Lua 在线编译器