在 Lua 中并没有像传统面向对象语言(如 Java、Python 等)那样内置的类和继承机制,但可以通过表(table)和元表(metatable)来模拟实现类、继承、封装和多态的概念。下面将详细介绍如何实现这些特性,并给出具体的代码示例。
在 Lua 中,可以使用表来表示类,通过定义一个构造函数来创建类的实例。
-- 定义一个类
local Person = {}
-- 构造函数
function Person:new(name, age)
-- 创建一个新的实例
local instance = {
name = name,
age = age
}
-- 将 instance 的元表设置为 self(也就是 Person)
setmetatable(instance, self)
-- 当在 instance 中查找不存在的键时,会在 self(Person)中查找
self.__index = self
-- 返回新创建的实例
return instance
end
-- 类的方法
function Person:introduce()
print("My name is " .. self.name .. ", and I'm " .. self.age .. " years old.")
end
-- 创建类的实例
local person1 = Person:new("Alice", 25)
person1:introduce() -- 输出: My name is Alice, and I'm 25 years old.
在 Lua 里,使用冒号 : 来定义和调用函数时,会有特殊的参数传递规则。
在上述代码中:
可以通过修改元表来实现类的继承,子类可以继承父类的方法和属性。
基本思路
-- 定义一个类
local Person = {}
-- 构造函数
function Person:new(name, age)
-- 创建一个新的实例
local instance = {
name = name, -- 设置实例的 name 属性
age = age -- 设置实例的 age 属性
}
-- 将 instance 的元表设置为 self(也就是 Person)
setmetatable(instance, self)
-- 当在 instance 中查找不存在的键时,会在 self(Person)中查找
self.__index = self
-- 返回新创建的实例
return instance
end
-- 父类的方法
function Person:introduce()
-- 打印学生的自我介绍
print("My name is " .. self.name .. ", I'm " .. self.age .. " years old")
end
-- 子类
local Student = {}
-- 继承 Person 类,设置 Student 的元表为 Person
setmetatable(Student, {__index = Person})
-- 子类的构造函数
function Student:new(name, age, grade)
-- 调用父类的构造函数创建一个新的实例
local instance = Person:new(name, age)
-- 添加子类特有的属性 grade
instance.grade = grade
-- 将 instance 的元表设置为 self(也就是 Student)
setmetatable(instance, self)
-- 当在 instance 中查找不存在的键时,会在 self(Student)中查找
self.__index = self
-- 返回新创建的实例
return instance
end
-- 子类的方法
function Student:introduce()
-- 打印学生的自我介绍
print("My name is " .. self.name .. ", I'm " .. self.age .. " years old, and I'm in grade " .. self.grade .. ".")
end
-- 创建子类的实例
local student1 = Student:new("Bob", 18, 12)
-- 调用子类的方法
student1:introduce() -- 输出: My name is Bob, I'm 18 years old, and I'm in grade 12.
代码解释
基本思路
多重继承意味着一个子类可以有多个父类。实现多重继承的关键在于自定义 __index 元方法,当在子类中查找某个键时,依次在各个父类中查找。
-- 定义第一个父类
local Flying = {}
-- 定义 Flying 类的方法 fly
function Flying:fly()
-- 打印当前实例的 name 属性,表示正在飞行
print(self.name .. " is flying.")
end
-- 定义第二个父类
local Swimming = {}
-- 定义 Swimming 类的方法 swim
function Swimming:swim()
-- 打印当前实例的 name 属性,表示正在游泳
print(self.name .. " is swimming.")
end
-- 定义子类
local Duck = {}
-- 多重继承辅助函数
local function search(k, parents)
-- 遍历父类列表
for _, parent in ipairs(parents) do
-- 在父类中查找键 k
local v = parent[k]
-- 如果找到,则返回对应的方法或属性
if v then return v end
end
end
-- 设置 Duck 的元表
function Duck:new(name)
-- 创建一个新的实例,并初始化 name 属性
local instance = {
name = name
}
-- 定义父类列表
local parents = {Flying, Swimming}
-- 设置实例的元表
setmetatable(instance, {
-- 当在实例中查找不存在的键时,调用 __index 函数
__index = function(t, k)
-- 在父类列表中查找键 k
return search(k, parents)
end
})
-- 返回新创建的实例
return instance
end
-- 创建子类实例
local duck = Duck:new("Donald")
-- 调用从 Flying 类继承的 fly 方法
duck:fly() -- 输出: Donald is flying.
-- 调用从 Swimming 类继承的 swim 方法
duck:swim() -- 输出: Donald is swimming.
代码解释
在 Lua 中,可以通过闭包来实现封装,将一些属性和方法隐藏起来,只提供公共的接口。
local function createPerson(name, age)
-- 私有属性
local privateName = name
local privateAge = age
-- 公共接口
local public = {}
function public:introduce()
print("My name is " .. privateName .. ", and I'm " .. privateAge .. " years old.")
end
return public
end
-- 创建实例
local person2 = createPerson("Charlie", 30)
person2:introduce() -- 输出: My name is Charlie, and I'm 30 years old.
多态是指不同的对象对同一消息做出不同的响应。在 Lua 中,可以通过继承和方法重写来实现多态。
-- 父类 Shape
local Shape = {} -- 定义一个空表 Shape,作为父类
-- Shape 的构造函数
function Shape:new()
local instance = {} -- 创建一个新的实例表
setmetatable(instance, self) -- 将实例的元表设置为 Shape
self.__index = self -- 设置 Shape 的 __index 元方法为自身,用于方法查找
return instance -- 返回新创建的实例
end
-- Shape 的 area 方法(默认实现,返回 0)
function Shape:area()
return 0 -- 默认面积为 0
end
-- 子类:圆形 Circle
local Circle = {} -- 定义一个空表 Circle,作为子类
setmetatable(Circle, {__index = Shape}) -- 设置 Circle 的元表为 Shape,实现继承
-- Circle 的构造函数
function Circle:new(radius)
local instance = Shape:new() -- 调用父类的构造函数创建实例
instance.radius = radius -- 添加 radius 属性
setmetatable(instance, self) -- 将实例的元表设置为 Circle
self.__index = self -- 设置 Circle 的 __index 元方法为自身
return instance -- 返回新创建的实例
end
-- Circle 的 area 方法(重写父类方法)
function Circle:area()
return math.pi * self.radius * self.radius -- 计算并返回圆形的面积
end
-- 子类:矩形 Rectangle
local Rectangle = {} -- 定义一个空表 Rectangle,作为子类
setmetatable(Rectangle, {__index = Shape}) -- 设置 Rectangle 的元表为 Shape,实现继承
-- Rectangle 的构造函数
function Rectangle:new(width, height)
local instance = Shape:new() -- 调用父类的构造函数创建实例
instance.width = width -- 添加 width 属性
instance.height = height -- 添加 height 属性
setmetatable(instance, self) -- 将实例的元表设置为 Rectangle
self.__index = self -- 设置 Rectangle 的 __index 元方法为自身
return instance -- 返回新创建的实例
end
-- Rectangle 的 area 方法(重写父类方法)
function Rectangle:area()
return self.width * self.height -- 计算并返回矩形的面积
end
-- 多态示例:打印任意形状的面积
local function printArea(shape)
print("The area of the shape is: " .. shape:area()) -- 调用 shape 的 area 方法并打印结果
end
-- 创建 Circle 和 Rectangle 的实例
local circle = Circle:new(5) -- 创建一个半径为 5 的圆形
local rectangle = Rectangle:new(4, 6) -- 创建一个宽 4、高 6 的矩形
-- 调用 printArea 函数,展示多态行为
printArea(circle) -- 输出: The area of the shape is: 78.539816339745
printArea(rectangle) -- 输出: The area of the shape is: 24
代码总结:
类的定义:
构造函数:
方法重写:
多态:
代码结构: