浅谈Lua的面向对象特性
面向对象编程是很多现代语言的基石,它的核心要素其实就那么几条。 类:可以把它理解为一个可扩展的模板,用来创建对象。它定义了对象的初始状态(成员变量)和行为(方法)。 对象:类是蓝图,对象就是根据蓝图造出来的具体实例,每个实例都有自己独立的内存空间。 继承:一个类可以继承另一个类的变量和函数,实现代码
面向对象编程是很多现代语言的基石,它的核心要素其实就那么几条。

- 类:可以把它理解为一个可扩展的模板,用来创建对象。它定义了对象的初始状态(成员变量)和行为(方法)。
- 对象:类是蓝图,对象就是根据蓝图造出来的具体实例,每个实例都有自己独立的内存空间。
- 继承:一个类可以继承另一个类的变量和函数,实现代码复用和扩展。
- 封装:把数据和操作数据的方法捆绑在一起,对外部隐藏内部细节,只通过公开的函数来访问。这通常也被称为数据抽象。
那么,在Lua这样一个轻巧的脚本语言里,怎么玩转面向对象呢?
答案是靠表(table)和第一类函数(first-class function)。把函数和相关数据塞进一个表里,就形成了一个对象。而继承,则是借助元表(metatable)的力量,实现一种查找机制——当在子对象中找不到某个函数(方法)或字段时,会自动去父对象里找。
Lua的表天然具有状态和标识,这跟对象的概念非常契合。两个表,即使内容一样,也是两个不同的对象;而同一个表,即使它的内容经常变化,它自己还是它。就跟你我一样,表也有自己的生命周期,独立存在。
为了把抽象的概念讲明白,我们来看一个数学例子。在工作中,我们经常会碰到各种形状,比如圆形、长方形、正方形。这些形状都有一个共同的属性:面积。所以,我们可以从一个基础的“形状”对象出发,让它派生其他的形状。每个形状都有自己的属性和方法。比如矩形,它有长度、宽度这些属性,也有计算面积和打印面积这些函数。
创建一个简单的类
下面这个例子,实现了一个简单的矩形类,它有面积、长度和宽度三个属性,以及一个打印面积的函数。
Rectangle = {area = 0, length = 0, breadth = 0}
-- Derived class method new
function Rectangle:new (o,length,breadth)
o = o or {}
setmetatable(o, self)
self.__index = self
self.length = length or 0
self.breadth = breadth or 0
self.area = length*breadth;
return o
end
-- Derived class method printArea
function Rectangle:printArea ()
print("The area of Rectangle is ",self.area)
end
创建对象
创建对象,就是为类的实例分配内存的过程。每个对象有自己的内存,同时共享类的公共数据。
访问属性
访问属性就用点操作符。
访问成员函数
访问对象的成员函数,用的是冒号运算符。
在这个过程中,内存被分配,初始值被设定。这个初始化过程,你可以把它类比成其他语言里的构造器。它本质上就是一个设定值的函数,上面已经演示得很清楚了。
完整例子
下面是一个在Lua中使用面向对象的完整示例。
Shape = {area = 0}
-- Base class method new
function Shape:new (o,side)
o = o or {}
setmetatable(o, self)
self.__index = self
side = side or 0
self.area = side*side;
return o
end
-- Base class method printArea
function Shape:printArea ()
print("The area is ",self.area)
end
-- Creating an object
myshape = Shape:new(nil,10)
myshape:printArea()
运行这段代码,输出如下:
Lua的继承
继承让我们可以从一个基础的“形状”对象出发,派生出“矩形”、“正方形”这些更具体的类。这正是现实世界中进行代码复用和扩展的基本手法。
我们先定义一个基类Shape。
Shape = {area = 0}
-- Base class method new
function Shape:new (o,side)
o = o or {}
setmetatable(o, self)
self.__index = self
side = side or 0
self.area = side*side;
return o
end
-- Base class method printArea
function Shape:printArea ()
print("The area is ",self.area)
end
然后,我们从这个Shape基类扩展出一个Square类。
-- Derived class method new
function Square:new (o,side)
o = o or Shape:new(o,side)
setmetatable(o, self)
self.__index = self
return o
end
重载基类方法
当然,派生类也可以覆盖基类的方法。比如,我们让正方形自己实现打印面积的函数,而不使用基类的那个。
function Square:printArea ()
print("The area of square is ",self.area)
end
继承的完整示例
Lua中,借助元表,我们可以非常简单地对一个类进行扩展,生成新的子类。基类所有的成员变量和函数,都会被派生类保留。
Shape = {area = 0}
-- Base class method new
function Shape:new (o,side)
o = o or {}
setmetatable(o, self)
self.__index = self
side = side or 0
self.area = side*side;
return o
end
-- Base class method printArea
function Shape:printArea ()
print("The area is ",self.area)
end
-- Creating an object
myshape = Shape:new(nil,10)
myshape:printArea()
Square = Shape:new()
-- Derived class method new
function Square:new (o,side)
o = o or Shape:new(o,side)
setmetatable(o, self)
self.__index = self
return o
end
-- Derived class method printArea
function Square:printArea ()
print("The area of square is ",self.area)
end
-- Creating an object
mysquare = Square:new(nil,10)
mysquare:printArea()
Rectangle = Shape:new()
-- Derived class method new
function Rectangle:new (o,length,breadth)
o = o or Shape:new(o)
setmetatable(o, self)
self.__index = self
self.area = length * breadth
return o
end
-- Derived class method printArea
function Rectangle:printArea ()
print("The area of Rectangle is ",self.area)
end
-- Creating an object
myrectangle = Rectangle:new(nil,10,20)
myrectangle:printArea()
运行之后,输出结果如下:
The area of square is 100
The area of Rectangle is 200
在这个例子中,我们从基类Shape派生出了Rectangle和Square两个子类,它们各自重写了printArea函数。这正是面向对象中“多态”的体现:同样的方法名,在不同对象上有不同的行为。
Windows 10 是一款微软推出的经典操作系统,拥有硬件兼容性与多任务处理能力。它更偏向把系统状态查看和常用调节动作放在一起,适合需要持续观察和微调设备状态的场景。
极度公式是一款跨平台专业LaTeX公式识别编辑软件,支持OCR公式识别和多平台编辑。和使用说明,避免使用,享受完整功能与稳定支持。做扫描整理、文字提取和表格转换时,它能把识别后的处理步骤接得更顺,资料录入这类场景会省下不少时间。
















