Menu
CoddyTech

共享与独有

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

使用继承时,了解每条数据存储的位置很重要。有些属性是共享的:在父类中定义,所有子类都可以访问。另一些属性是独有的:专门在子类或实例中创建。

请看这个层级结构:

local Animal = {}
Animal.__index = Animal
Animal.kingdom = "Animalia"  -- 共享:定义在类上

function Animal:new(name)
    local obj = {name = name}  -- 独有:存储在每个实例中
    setmetatable(obj, Animal)
    return obj
end
local Dog = {}
Dog.__index = Dog
setmetatable(Dog, {__index = Animal})
Dog.sound = "bark"  -- 所有 Dog 对象共享

function Dog:new(name, breed)
    local obj = Animal.new(Animal, name)
    obj.breed = breed  -- 每个 Dog 对象都有自己的 breed 属性
    setmetatable(obj, Dog)
    return obj
end

创建 Dog 实例时,有些值直接存在于对象上,另一些则需要通过查找链获取:

local rex = Dog:new("Rex", "German Shepherd")

-- 这个实例独有(存储在 rex 上)
print(rex.name)    -- "Rex"
print(rex.breed)   -- "German Shepherd"
-- 共享的属性(通过查找找到)
print(rex.sound)   -- "bark"(来自 Dog)
print(rex.kingdom) -- "Animalia"(来自 Animal)

关键区别是:在构造函数中赋给 obj 的字段是每个实例独有的,而直接定义在类表上的字段则由该类及其子类的所有实例共享。

challenge icon

挑战

简单

让我们通过构建一个 Creature 和 Dragon 类系统,探索数据如何在继承层级中流动。你将亲眼看到哪些属性由所有实例共享,哪些属性只属于每个对象。

你要把代码分成三个文件:

  • Creature.lua:定义父类,并添加一个由所有生物共享的类级属性 world = "Fantasy Realm"。再添加一个 :new(name) 构造函数,用于将生物的名称保存为实例属性。
  • Dragon.lua:定义一个继承自 Creature 的子类。添加一个由所有龙共享的类级属性 element = "fire"。你的 :new(name, color) 构造函数应先调用父类构造函数来处理名称,然后将 color 添加为每条龙各自独有的实例属性。
  • main.lua:创建两条不同的龙,并查看它们的属性,以展示共享数据和独有数据之间的区别。

你将收到两项输入:

  1. 第一条龙的名称和颜色,两者用逗号分隔(例如,Smaug,red)
  2. 第二条龙的名称和颜色,两者用逗号分隔(例如,Draco,gold)

在主文件中,使用各自的名称和颜色创建两条龙。然后严格按照以下顺序打印信息:

  1. 第一条龙的 name
  2. 第一条龙的 color
  3. 第二条龙的 name
  4. 第二条龙的 color
  5. 第一条龙的 element(从 Dragon 类共享)
  6. 第二条龙的 element(从 Dragon 类共享)
  7. 第一条龙的 world(从 Creature 类共享)

例如,如果输入是 Smaug,red 和 Draco,gold,输出应为:

Smaug
red
Draco
gold
fire
fire
Fantasy Realm

注意,name 和 color 对每条龙都不同(独有的实例属性),而 element 和 world 对两条龙都相同(通过查找链找到的共享类属性)。

亲手试试

-- main.lua:创建龙并演示共享属性和独有属性

local Dragon = require('Dragon')

-- 读取第一条龙的输入(name,color)
local input1 = io.read()
-- 读取第二条龙的输入(name,color)
local input2 = io.read()

-- TODO:解析第一个输入,提取名字和颜色
-- 提示:使用 string.match,模式为 "([^,]+),([^,]+)"

-- TODO:解析第二个输入,提取名字和颜色

-- TODO:用名字和颜色创建第一条龙

-- TODO:用名字和颜色创建第二条龙

-- TODO:按顺序输出以下内容:
-- 1. 第一条龙的名字
-- 2. 第一条龙的颜色
-- 3. 第二条龙的名字
-- 4. 第二条龙的颜色
-- 5. 第一条龙的元素属性(由 Dragon 类共享)
-- 6. 第二条龙的元素属性(由 Dragon 类共享)
-- 7. 第一条龙的世界属性(由 Creature 类共享)
quiz icon自我测试

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

面向对象编程中的所有课

自己练习: Lua 在线编译器