Lua 面向对象编程教程

本教程基于 oop.lua 文件,详细介绍 Lua 编程语言中的面向对象编程(OOP)相关知识。虽然 Lua 本身不是一种传统的面向对象编程语言,但它提供了强大的机制来实现面向对象编程范式。

目录

  1. 基本类实现
  2. 继承实现
  3. 多重继承(使用mixin方式)
  4. 私有属性模拟
  5. 类的静态属性和方法
  6. 多态示例
  7. 额外内容:高级OOP特性

1. 基本类实现

在 Lua 中,类通常使用表来实现。通过元表(metatable)机制,可以实现对象的方法调用和属性访问。

基本类结构

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
-- 定义一个简单的Person类
Person = {}

-- 构造函数
function Person:new(name, age)
-- 创建新对象,继承Person的所有属性和方法
local obj = {}
setmetatable(obj, self)
self.__index = self

-- 初始化对象属性
obj.name = name
obj.age = age

return obj
end

-- 成员方法
function Person:greet()
print("Hello, my name is " .. self.name .. " and I'm " .. self.age .. " years old.")
end

-- 成员方法
function Person:set_age(new_age)
self.age = new_age
print(self.name .. "'s age is now " .. self.age)
end

创建和使用对象

1
2
3
4
5
6
7
8
9
10
11
-- 创建Person对象
local person1 = Person:new("Alice", 25)
local person2 = Person:new("Bob", 30)

-- 调用对象方法
person1:greet()
person2:greet()

-- 修改对象属性
person1:set_age(26)
person1:greet()

额外示例:使用点语法定义方法

1
2
3
4
5
6
7
-- 也可以使用点语法定义方法,然后在调用时手动传递self
function Person.greet(self)
print("Hello, my name is " .. self.name .. " and I'm " .. self.age .. " years old.")
end

-- 使用点语法调用
Person.greet(person1)

2. 继承实现

Lua 通过元表机制实现继承。子类可以继承父类的所有属性和方法,并且可以重写或添加自己的方法。

基本继承实现

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
-- 定义Student类,继承自Person
Student = Person:new()

-- 学生构造函数
function Student:new(name, age, student_id, major)
-- 调用父类构造函数
local obj = Person:new(name, age)
setmetatable(obj, self)
self.__index = self

-- 初始化Student特有的属性
obj.student_id = student_id
obj.major = major

return obj
end

-- 重写父类方法
function Student:greet()
print("Hello, I'm " .. self.name .. ", a " .. self.major .. " student with ID " .. self.student_id .. ".")
end

-- 添加Student特有的方法
function Student:study(subject)
print(self.name .. " is studying " .. subject .. ".")
end

使用继承

1
2
3
4
5
6
7
8
9
10
11
-- 创建Student对象
local student1 = Student:new("Charlie", 20, "S12345", "Computer Science")
local student2 = Student:new("Diana", 21, "S67890", "Mathematics")

-- 调用方法
student1:greet() -- 调用重写后的方法
student1:study("Lua Programming")
student1:set_age(21) -- 调用继承的方法

student2:greet()
student2:study("Calculus")

额外示例:调用父类方法

1
2
3
4
5
6
7
8
9
10
-- 在子类中调用父类方法
function Student:greet()
-- 调用父类的greet方法
Person.greet(self)
-- 添加子类特有的内容
print("I'm a " .. self.major .. " student with ID " .. self.student_id .. ".")
end

-- 测试
student1:greet()

3. 多重继承(使用mixin方式)

Lua 本身不直接支持多重继承,但可以通过混入(mixin)的方式模拟多重继承。Mixin 是一种将一组方法注入到类中的技术。

实现Mixin

1
2
3
4
5
6
7
8
9
10
11
12
13
-- 定义一个CanSwim mixin
CanSwim = {
swim = function(self)
print(self.name .. " is swimming.")
end
}

-- 定义一个CanFly mixin
CanFly = {
fly = function(self)
print(self.name .. " is flying.")
end
}

使用Mixin实现多重继承

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
-- 定义Bird类,继承Person并混合CanFly
Bird = Person:new()

function Bird:new(name, age, wingspan)
local obj = Person:new(name, age)
setmetatable(obj, self)
self.__index = self

-- 添加CanFly方法
for k, v in pairs(CanFly) do
if not obj[k] then
obj[k] = v
end
end

obj.wingspan = wingspan
return obj
end

function Bird:greet()
print("Chirp! I'm " .. self.name .. " with a " .. self.wingspan .. "cm wingspan.")
end

-- 定义Duck类,继承Bird并混合CanSwim
Duck = Bird:new()

function Duck:new(name, age, wingspan)
local obj = Bird:new(name, age, wingspan)
setmetatable(obj, self)
self.__index = self

-- 添加CanSwim方法
for k, v in pairs(CanSwim) do
if not obj[k] then
obj[k] = v
end
end

return obj
end

function Duck:greet()
print("Quack! I'm " .. self.name .. ".")
end

使用多重继承

1
2
3
4
5
6
-- 创建Duck对象
local duck = Duck:new("Donald", 5, 60)
duck:greet()
duck:fly() -- 来自CanFly mixin
duck:swim() -- 来自CanSwim mixin
duck:set_age(6) -- 继承自Person的方法

额外示例:Mixin管理

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
-- 创建一个Mixin管理器
local MixinManager = {
mixins = {}
}

function MixinManager:register_mixin(name, mixin)
self.mixins[name] = mixin
end

function MixinManager:apply_mixin(obj, mixin_name)
local mixin = self.mixins[mixin_name]
if mixin then
for k, v in pairs(mixin) do
if not obj[k] then
obj[k] = v
end
end
return true
end
return false
end

-- 使用Mixin管理器
local mm = MixinManager:new()
mm:register_mixin("CanSwim", CanSwim)
mm:register_mixin("CanFly", CanFly)

-- 应用多个mixin
local super_creature = Person:new("Super Creature", 100)
mm:apply_mixin(super_creature, "CanSwim")
mm:apply_mixin(super_creature, "CanFly")

super_creature:swim()
super_creature:fly()

4. 私有属性模拟

Lua 没有内置的私有属性机制,但可以通过闭包(closure)来模拟私有属性。

使用闭包实现私有属性

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
-- 使用闭包模拟私有属性
function create_private_person(name, age)
-- 私有属性
local private_name = name
local private_age = age

-- 公共接口
local obj = {}

obj.get_name = function()
return private_name
end

obj.get_age = function()
return private_age
end

obj.set_age = function(new_age)
if new_age > 0 then
private_age = new_age
return true
end
return false
end

obj.greet = function()
print("Hello, my name is " .. private_name .. " and I'm " .. private_age .. " years old.")
end

return obj
end

使用私有属性

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
-- 创建带有私有属性的person对象
local private_person = create_private_person("Eve", 35)
private_person:greet()
print("Name:", private_person.get_name())
print("Age:", private_person.get_age())

-- 尝试直接访问私有属性(会失败)
print("Can access private_name directly?", private_person.private_name) -- nil

-- 使用公共方法修改年龄
private_person.set_age(36)
private_person:greet()

-- 尝试设置无效年龄
local success = private_person.set_age(-5)
print("Setting invalid age succeeded?", success)

额外示例:混合公有和私有属性

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
-- 混合公有和私有属性
function create_mixed_person(name, age)
-- 私有属性
local private_age = age

-- 公共接口
local obj = {
name = name -- 公有属性
}

obj.get_age = function()
return private_age
end

obj.set_age = function(new_age)
if new_age > 0 then
private_age = new_age
return true
end
return false
end

obj.greet = function()
print("Hello, my name is " .. obj.name .. " and I'm " .. private_age .. " years old.")
end

return obj
end

local mixed_person = create_mixed_person("Frank", 40)
mixed_person:greet()
print("Public name:", mixed_person.name) -- 可以直接访问
print("Private age (via getter):", mixed_person.get_age()) -- 只能通过 getter 访问

5. 类的静态属性和方法

静态属性和方法属于类本身,而不是类的实例。在 Lua 中,可以直接在类表上定义静态属性和方法。

实现静态属性和方法

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
-- 定义一个带有静态属性和方法的类
Counter = {
count = 0, -- 静态属性
instances = {}
}

function Counter:new()
local obj = {}
setmetatable(obj, self)
self.__index = self

-- 增加实例计数
self.count = self.count + 1
table.insert(self.instances, obj)

return obj
end

-- 静态方法
function Counter.get_total_instances()
return Counter.count
end

-- 静态方法
function Counter.reset()
Counter.count = 0
Counter.instances = {}
print("Counter reset.")
end

使用静态属性和方法

1
2
3
4
5
6
7
8
9
10
11
12
-- 创建Counter实例
local counter1 = Counter:new()
local counter2 = Counter:new()
local counter3 = Counter:new()

-- 访问静态属性和方法
print("Total Counter instances:", Counter.get_total_instances()) -- 调用静态方法
print("Static count attribute:", Counter.count) -- 访问静态属性

-- 重置计数器
Counter.reset()
print("Total Counter instances after reset:", Counter.get_total_instances())

额外示例:静态方法的另一种实现

1
2
3
4
5
6
7
8
-- 使用冒号语法定义静态方法
function Counter:static_method()
-- 注意:这里的 self 指向 Counter 类本身
print("Static method called, count is:", self.count)
end

-- 调用静态方法
Counter:static_method()

6. 多态示例

多态是面向对象编程的重要特性,允许不同类型的对象对相同的消息做出不同的响应。在 Lua 中,可以通过方法重写实现多态。

定义抽象基类

1
2
3
4
5
6
7
8
9
10
11
12
13
14
-- 定义一个接口类
Shape = {}

function Shape:new()
local obj = {}
setmetatable(obj, self)
self.__index = self
return obj
end

-- 抽象方法(应该被子类重写)
function Shape:area()
error("Abstract method 'area' must be implemented by subclass")
end

定义子类

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
-- Circle类
Circle = Shape:new()

function Circle:new(radius)
local obj = Shape:new()
setmetatable(obj, self)
self.__index = self
obj.radius = radius
return obj
end

function Circle:area()
return math.pi * self.radius * self.radius
end

-- Rectangle类
Rectangle = Shape:new()

function Rectangle:new(width, height)
local obj = Shape:new()
setmetatable(obj, self)
self.__index = self
obj.width = width
obj.height = height
return obj
end

function Rectangle:area()
return self.width * self.height
end

-- Square类
Square = Rectangle:new()

function Square:new(side)
local obj = Rectangle:new(side, side)
setmetatable(obj, self)
self.__index = self
return obj
end

使用多态

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
-- 多态函数,接受任何Shape类型
function print_area(shape)
print("Area:", shape:area())
end

-- 创建不同形状的对象
local circle = Circle:new(5)
local rectangle = Rectangle:new(4, 6)
local square = Square:new(5)

-- 调用多态函数
print("Circle area:")
print_area(circle)

print("Rectangle area:")
print_area(rectangle)

print("Square area:")
print_area(square)

额外示例:多态的实际应用

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
-- 多态的实际应用:图形渲染系统
local Renderer = {
render = function(self, shape)
print("Rendering shape with area:", shape:area())
-- 这里可以根据不同的形状类型执行不同的渲染逻辑
if shape.radius then
print("Rendering a circle with radius:", shape.radius)
elseif shape.width and shape.height then
print("Rendering a rectangle with width:", shape.width, "and height:", shape.height)
end
end
}

local renderer = Renderer:new()
renderer:render(circle)
renderer:render(rectangle)
renderer:render(square)

7. 额外内容:高级OOP特性

属性访问控制

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
-- 使用元表实现属性访问控制
local Person = {}

function Person:new(name, age)
local obj = {
_name = name, -- 约定以下划线开头的属性为私有
_age = age
}

local mt = {
__index = function(t, k)
-- 公共属性直接返回
if k == "name" then
return t._name
end
-- 其他属性通过方法访问
return Person[k]
end,

__newindex = function(t, k, v)
-- 防止直接修改私有属性
if k == "name" or k == "age" then
error("Cannot modify private property directly, use set_age method")
end
rawset(t, k, v)
end
}

setmetatable(obj, mt)
return obj
end

function Person:set_age(new_age)
if new_age > 0 then
self._age = new_age
return true
end
return false
end

function Person:greet()
print("Hello, my name is " .. self._name .. " and I'm " .. self._age .. " years old.")
end

local person = Person:new("Grace", 28)
print("Name:", person.name) -- 可以访问
-- person.name = "New Name" -- 会报错
person:set_age(29)
person:greet()

链式方法调用

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
-- 实现链式方法调用
local Person = {}

function Person:new(name, age)
local obj = {}
setmetatable(obj, self)
self.__index = self
obj.name = name
obj.age = age
return obj
end

function Person:set_name(name)
self.name = name
return self -- 返回self以支持链式调用
end

function Person:set_age(age)
self.age = age
return self -- 返回self以支持链式调用
end

function Person:greet()
print("Hello, my name is " .. self.name .. " and I'm " .. self.age .. " years old.")
return self -- 返回self以支持链式调用
end

-- 使用链式调用
local person = Person:new("Henry", 30)
person:set_name("Harry"):set_age(31):greet()

类的模块化

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
-- 将类封装到模块中
-- person.lua
local Person = {}

function Person:new(name, age)
local obj = {}
setmetatable(obj, self)
self.__index = self
obj.name = name
obj.age = age
return obj
end

function Person:greet()
print("Hello, my name is " .. self.name .. " and I'm " .. self.age .. " years old.")
end

return Person

-- 使用模块
local Person = require("person")
local person = Person:new("Ivy", 25)
person:greet()

运行示例

要运行 oop.lua 文件,只需在命令行中执行:

1
lua oop.lua

运行结果将显示各个部分的输出,包括类的创建、继承、多重继承、私有属性、静态方法和多态的示例。

总结

本教程介绍了 Lua 编程语言中的面向对象编程相关知识,包括:

  • 基本类实现:使用表和元表创建类和对象
  • 继承实现:通过元表机制实现类的继承
  • 多重继承:使用mixin方式模拟多重继承
  • 私有属性:使用闭包模拟私有属性
  • 静态属性和方法:在类表上定义静态成员
  • 多态:通过方法重写实现多态
  • 高级特性:属性访问控制、链式方法调用和类的模块化

虽然 Lua 不是一种传统的面向对象编程语言,但通过上述技术,可以实现功能完备的面向对象编程范式。Lua 的面向对象实现方式灵活多样,可以根据具体需求选择最合适的方法。

oop.lua

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
-- Lua面向对象编程示例
-- print语句使用英语,注释使用中文

-- 1. 基本类实现
print("=== Basic Class Implementation ===")

-- 定义一个简单的Person类
Person = {}

-- 构造函数
function Person:new(name, age)
-- 创建新对象,继承Person的所有属性和方法
local obj = {}
setmetatable(obj, self)
self.__index = self

-- 初始化对象属性
obj.name = name
obj.age = age

return obj
end

-- 成员方法
function Person:greet()
print("Hello, my name is " .. self.name .. " and I'm " .. self.age .. " years old.")
end

-- 成员方法
function Person:set_age(new_age)
self.age = new_age
print(self.name .. "'s age is now " .. self.age)
end

-- 创建Person对象
local person1 = Person:new("Alice", 25)
local person2 = Person:new("Bob", 30)

-- 调用对象方法
person1:greet()
person2:greet()

-- 修改对象属性
person1:set_age(26)
person1:greet()

-- 2. 继承实现
print("\n=== Inheritance Implementation ===")

-- 定义Student类,继承自Person
Student = Person:new()

-- 学生构造函数
function Student:new(name, age, student_id, major)
-- 调用父类构造函数
local obj = Person:new(name, age)
setmetatable(obj, self)
self.__index = self

-- 初始化Student特有的属性
obj.student_id = student_id
obj.major = major

return obj
end

-- 重写父类方法
function Student:greet()
print("Hello, I'm " .. self.name .. ", a " .. self.major .. " student with ID " .. self.student_id .. ".")
end

-- 添加Student特有的方法
function Student:study(subject)
print(self.name .. " is studying " .. subject .. ".")
end

-- 创建Student对象
local student1 = Student:new("Charlie", 20, "S12345", "Computer Science")
local student2 = Student:new("Diana", 21, "S67890", "Mathematics")

-- 调用方法
student1:greet() -- 调用重写后的方法
student1:study("Lua Programming")
student1:set_age(21) -- 调用继承的方法

student2:greet()
student2:study("Calculus")

-- 3. 多重继承(使用mixin方式)
print("\n=== Multiple Inheritance (Mixin Approach) ===")

-- 定义一个CanSwim mixin
CanSwim = {
swim = function(self)
print(self.name .. " is swimming.")
end
}

-- 定义一个CanFly mixin
CanFly = {
fly = function(self)
print(self.name .. " is flying.")
end
}

-- 定义Bird类,继承Person并混合CanFly
Bird = Person:new()

function Bird:new(name, age, wingspan)
local obj = Person:new(name, age)
setmetatable(obj, self)
self.__index = self

-- 添加CanFly方法
for k, v in pairs(CanFly) do
if not obj[k] then
obj[k] = v
end
end

obj.wingspan = wingspan
return obj
end

function Bird:greet()
print("Chirp! I'm " .. self.name .. " with a " .. self.wingspan .. "cm wingspan.")
end

-- 定义Duck类,继承Bird并混合CanSwim
Duck = Bird:new()

function Duck:new(name, age, wingspan)
local obj = Bird:new(name, age, wingspan)
setmetatable(obj, self)
self.__index = self

-- 添加CanSwim方法
for k, v in pairs(CanSwim) do
if not obj[k] then
obj[k] = v
end
end

return obj
end

function Duck:greet()
print("Quack! I'm " .. self.name .. ".")
end

-- 创建Duck对象
local duck = Duck:new("Donald", 5, 60)
duck:greet()
duck:fly()
duck:swim()
duck:set_age(6) -- 继承自Person的方法

-- 4. 私有属性模拟
print("\n=== Private Property Simulation ===")

-- 使用闭包模拟私有属性
function create_private_person(name, age)
-- 私有属性
local private_name = name
local private_age = age

-- 公共接口
local obj = {}

obj.get_name = function()
return private_name
end

obj.get_age = function()
return private_age
end

obj.set_age = function(new_age)
if new_age > 0 then
private_age = new_age
return true
end
return false
end

obj.greet = function()
print("Hello, my name is " .. private_name .. " and I'm " .. private_age .. " years old.")
end

return obj
end

-- 创建带有私有属性的person对象
local private_person = create_private_person("Eve", 35)
private_person:greet()
print("Name:", private_person.get_name())
print("Age:", private_person.get_age())

-- 尝试直接访问私有属性(会失败)
print("Can access private_name directly?", private_person.private_name) -- nil

-- 使用公共方法修改年龄
private_person.set_age(36)
private_person:greet()

-- 尝试设置无效年龄
local success = private_person.set_age(-5)
print("Setting invalid age succeeded?", success)

-- 5. 类的静态属性和方法
print("\n=== Class Static Properties and Methods ===")

-- 定义一个带有静态属性和方法的类
Counter = {
count = 0, -- 静态属性
instances = {}
}

function Counter:new()
local obj = {}
setmetatable(obj, self)
self.__index = self

-- 增加实例计数
self.count = self.count + 1
table.insert(self.instances, obj)

return obj
end

-- 静态方法
function Counter.get_total_instances()
return Counter.count
end

-- 静态方法
function Counter.reset()
Counter.count = 0
Counter.instances = {}
print("Counter reset.")
end

-- 创建Counter实例
local counter1 = Counter:new()
local counter2 = Counter:new()
local counter3 = Counter:new()

-- 访问静态属性和方法
print("Total Counter instances:", Counter.get_total_instances()) -- 调用静态方法
print("Static count attribute:", Counter.count) -- 访问静态属性

-- 重置计数器
Counter.reset()
print("Total Counter instances after reset:", Counter.get_total_instances())

-- 6. 多态示例
print("\n=== Polymorphism Example ===")

-- 定义一个接口类
Shape = {}

function Shape:new()
local obj = {}
setmetatable(obj, self)
self.__index = self
return obj
end

-- 抽象方法(应该被子类重写)
function Shape:area()
error("Abstract method 'area' must be implemented by subclass")
end

-- Circle类
Circle = Shape:new()

function Circle:new(radius)
local obj = Shape:new()
setmetatable(obj, self)
self.__index = self
obj.radius = radius
return obj
end

function Circle:area()
return math.pi * self.radius * self.radius
end

-- Rectangle类
Rectangle = Shape:new()

function Rectangle:new(width, height)
local obj = Shape:new()
setmetatable(obj, self)
self.__index = self
obj.width = width
obj.height = height
return obj
end

function Rectangle:area()
return self.width * self.height
end

-- Square类
Square = Rectangle:new()

function Square:new(side)
local obj = Rectangle:new(side, side)
setmetatable(obj, self)
self.__index = self
return obj
end

-- 多态函数,接受任何Shape类型
function print_area(shape)
print("Area:", shape:area())
end

-- 创建不同形状的对象
local circle = Circle:new(5)
local rectangle = Rectangle:new(4, 6)
local square = Square:new(5)

-- 调用多态函数
print("Circle area:")
print_area(circle)

print("Rectangle area:")
print_area(rectangle)

print("Square area:")
print_area(square)

Lua 表操作教程

本教程基于 tables.lua 文件,详细介绍 Lua 编程语言中的表(Table)相关知识。表是 Lua 中唯一的数据结构,非常灵活强大,可以用来表示数组、字典等各种数据结构。

目录

  1. 表的基本概念
  2. 数组(数值索引表)
  3. 字典(字符串索引表)
  4. 混合表
  5. 表遍历
  6. 表操作函数
  7. 嵌套表
  8. 表的拷贝
  9. 表的元表
  10. 额外内容:表的长度计算和特殊用法

1. 表的基本概念

表是 Lua 中唯一的数据结构,可以用来表示各种复杂的数据。表是一种关联数组,能够将不同类型的值(包括其他表)与键关联起来。

1
2
3
4
-- 空表
local empty_table = {}
print("Empty table:", empty_table)
print("Type of empty_table:", type(empty_table))

额外示例:表的创建方式

1
2
3
4
5
6
7
8
9
10
-- 直接创建表
local t1 = {} -- 空表
local t2 = {1, 2, 3} -- 数组形式
local t3 = {x = 10, y = 20} -- 字典形式

-- 使用构造函数创建表
local t4 = table.new(0, 2) -- 创建一个预分配空间的表(需要 LuaJIT)
print("Table t1:", t1)
print("Table t2:", t2)
print("Table t3:", t3)

2. 数组(数值索引表)

数组是一种使用数值作为索引的表。在 Lua 中,数组的索引从 1 开始,这与许多其他编程语言不同。

1
2
3
4
5
6
7
8
9
10
-- 整数索引表,索引从1开始
local fruits = {"apple", "banana", "orange", "grape"}
print("Fruits table:")
print("First fruit:", fruits[1]) -- Lua数组索引从1开始
print("Second fruit:", fruits[2])
print("Number of fruits:", #fruits) -- #操作符获取表长度

-- 手动指定索引
local numbers = {[1] = 10, [2] = 20, [3] = 30}
print("Numbers table:", numbers[1], numbers[2], numbers[3])

额外示例:稀疏数组

1
2
3
4
5
6
7
8
9
10
-- 稀疏数组:不是所有索引都有值的数组
local sparse_array = {}
sparse_array[1] = "first"
sparse_array[100] = "hundredth"
sparse_array[1000] = "thousandth"

print("Sparse array[1]:", sparse_array[1])
print("Sparse array[100]:", sparse_array[100])
print("Sparse array[1000]:", sparse_array[1000])
print("Length of sparse array:", #sparse_array) -- 只计算连续部分

3. 字典(字符串索引表)

字典是一种使用字符串作为键的表,也称为关联数组。在 Lua 中,可以使用点表示法或方括号表示法访问字典中的值。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
local person = {
name = "John",
age = 30,
city = "New York",
is_student = false
}

print("Person table:")
print("Name:", person.name) -- 点表示法
print("Age:", person["age"]) -- 方括号表示法

-- 添加新键值对
person.occupation = "Engineer"
person["salary"] = 50000
print("Occupation:", person.occupation)
print("Salary:", person.salary)

-- 删除键值对
person.is_student = nil
print("After deleting is_student:", person.is_student)

额外示例:使用动态键

1
2
3
4
5
6
7
8
9
-- 使用动态键
local key = "language"
local settings = {}
settings[key] = "Lua"
settings["version"] = "5.1"

print("Settings[language]:", settings[language]) -- 错误:language 未定义
print("Settings[key]:", settings[key]) -- 正确:使用变量作为键
print("Settings['language']:", settings["language"]) -- 正确:使用字符串字面量作为键

4. 混合表

混合表是同时包含数组部分(数值索引)和字典部分(字符串索引)的表。在 Lua 中,这两种部分可以共存于同一个表中。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
local mixed_table = {
"first", -- 索引1
"second", -- 索引2
name = "mixed",
value = 100,
"third" -- 索引3
}

print("Mixed table:")
print("Index 1:", mixed_table[1])
print("Index 2:", mixed_table[2])
print("Index 3:", mixed_table[3])
print("Name:", mixed_table.name)
print("Value:", mixed_table.value)
print("Length of mixed_table:", #mixed_table) -- 只计算数组部分

额外示例:混合表的应用

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
-- 混合表的应用:表示一个游戏角色
local player = {
"warrior", -- 职业
"level 10", -- 等级
name = "Hero",
hp = 100,
mp = 50,
inventory = {"sword", "shield", "potion"}
}

print("Player class:", player[1])
print("Player level:", player[2])
print("Player name:", player.name)
print("Player HP:", player.hp)
print("Player inventory:", table.concat(player.inventory, ", "))

5. 表遍历

Lua 提供了两种主要的表遍历方式:ipairspairs

使用 ipairs 遍历数组部分

ipairs 函数用于遍历表的数组部分,只遍历连续的数值索引,按顺序从 1 开始。

1
2
3
4
5
-- 使用ipairs遍历数组部分(仅遍历数值索引,按顺序)
print("Using ipairs to iterate fruits:")
for index, fruit in ipairs(fruits) do
print("Index", index, ":", fruit)
end

使用 pairs 遍历整个表

pairs 函数用于遍历整个表,包括数组部分和字典部分,遍历顺序是不确定的。

1
2
3
4
5
6
7
8
9
10
11
-- 使用pairs遍历整个表(包括数组和字典部分,无序)
print("\nUsing pairs to iterate person:")
for key, value in pairs(person) do
print(key, ":", value)
end

-- 遍历混合表
print("\nUsing pairs to iterate mixed_table:")
for key, value in pairs(mixed_table) do
print(key, ":", value)
end

额外示例:遍历技巧

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
-- 按顺序遍历字典键
local sorted_person = {}
for key in pairs(person) do
table.insert(sorted_person, key)
end
table.sort(sorted_person)

print("Sorted keys in person:")
for _, key in ipairs(sorted_person) do
print(key, ":", person[key])
end

-- 遍历指定范围的数组
local numbers = {10, 20, 30, 40, 50, 60, 70}
print("Numbers from index 2 to 5:")
for i = 2, 5 do
print("Index", i, ":", numbers[i])
end

6. 表操作函数

Lua 提供了一组内置的表操作函数,位于 table 模块中。

table.insert:插入元素

1
2
3
4
5
6
7
8
9
-- table.insert:在指定位置插入元素
local numbers = {1, 2, 3, 4, 5}
print("Original numbers:", table.concat(numbers, ", "))

table.insert(numbers, 3, 100) -- 在索引3处插入100
print("After table.insert(numbers, 3, 100):", table.concat(numbers, ", "))

table.insert(numbers, 200) -- 在末尾插入200
print("After table.insert(numbers, 200):", table.concat(numbers, ", "))

table.remove:删除元素

1
2
3
4
5
6
7
8
-- table.remove:删除指定位置的元素
local removed = table.remove(numbers, 3) -- 删除索引3处的元素
print("Removed element:", removed)
print("After table.remove(numbers, 3):", table.concat(numbers, ", "))

removed = table.remove(numbers) -- 删除末尾元素
print("Removed element:", removed)
print("After table.remove(numbers):", table.concat(numbers, ", "))

table.sort:排序

1
2
3
4
5
6
7
8
9
10
11
12
-- table.sort:排序
local unsorted = {5, 2, 8, 1, 9, 3}
print("\nUnsorted:", table.concat(unsorted, ", "))

table.sort(unsorted)
print("Sorted ascending:", table.concat(unsorted, ", "))

-- 降序排序
table.sort(unsorted, function(a, b)
return a > b
end)
print("Sorted descending:", table.concat(unsorted, ", "))

table.concat:连接元素

1
2
3
4
5
6
7
-- table.concat:连接表元素为字符串
local words = {"Hello", "World", "Lua"}
local sentence = table.concat(words, " ")
print("\nConcatenated string:", sentence)

local numbers_str = table.concat({1, 2, 3, 4, 5}, "-")
print("Concatenated numbers:", numbers_str)

table.unpack:解包元素

1
2
3
4
-- table.unpack:将表元素作为可变参数返回
local coords = {10, 20, 30}
local x, y, z = unpack(coords) -- Lua 5.1 使用 unpack,Lua 5.2+ 使用 table.unpack
print("\nUnpacked coordinates:", x, y, z)

额外示例:其他表操作函数

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
-- 查找元素索引
function find_index(tbl, value)
for i, v in ipairs(tbl) do
if v == value then
return i
end
end
return nil
end

local fruits = {"apple", "banana", "orange", "grape"}
print("Index of 'banana':", find_index(fruits, "banana"))
print("Index of 'pear':", find_index(fruits, "pear"))

-- 反转表
function reverse_table(tbl)
local reversed = {}
for i = #tbl, 1, -1 do
table.insert(reversed, tbl[i])
end
return reversed
end

local reversed_fruits = reverse_table(fruits)
print("Reversed fruits:", table.concat(reversed_fruits, ", "))

7. 嵌套表

嵌套表是指表中包含其他表的情况,可以用来表示更复杂的数据结构,如二维数组、树等。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
local matrix = {
{1, 2, 3},
{4, 5, 6},
{7, 8, 9}
}

print("Matrix:")
for i = 1, #matrix do
local row = matrix[i]
print(table.concat(row, "\t"))
end

-- 访问嵌套表元素
print("Element at (2, 3):", matrix[2][3])

额外示例:嵌套表的应用

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
-- 嵌套表的应用:表示一个公司结构
local company = {
name = "Tech Corp",
departments = {
{
name = "Engineering",
employees = {
{name = "Alice", position = "Engineer"},
{name = "Bob", position = "Manager"}
}
},
{
name = "Marketing",
employees = {
{name = "Charlie", position = "Marketer"},
{name = "Diana", position = "Manager"}
}
}
}
}

print("Company name:", company.name)
print("Engineering department employees:")
for _, emp in ipairs(company.departments[1].employees) do
print(" ", emp.name, "-", emp.position)
end

8. 表的拷贝

表的拷贝分为浅拷贝和深拷贝两种方式。

浅拷贝

浅拷贝只复制表的顶层元素,对于嵌套表,只复制引用,不复制其内容。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
-- 浅拷贝示例
local original = {a = 1, b = {c = 2}}
local copy = {}
for key, value in pairs(original) do
copy[key] = value
end

print("Original.b.c:", original.b.c)
print("Copy.b.c:", copy.b.c)

-- 修改嵌套表,浅拷贝会影响原表
copy.b.c = 100
print("After modifying copy.b.c:")
print("Original.b.c:", original.b.c)
print("Copy.b.c:", copy.b.c)

深拷贝

深拷贝会递归复制表的所有元素,包括嵌套表,创建一个完全独立的副本。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
-- 深拷贝函数
function deep_copy(orig)
local orig_type = type(orig)
local copy
if orig_type == 'table' then
copy = {}
for orig_key, orig_value in next, orig, nil do
copy[deep_copy(orig_key)] = deep_copy(orig_value)
end
setmetatable(copy, deep_copy(getmetatable(orig)))
else -- 基本类型直接复制
copy = orig
end
return copy
end

-- 使用深拷贝
local deep_copy_table = deep_copy(original)
deep_copy_table.b.c = 200
print("\nAfter deep copy and modifying:")
print("Original.b.c:", original.b.c)
print("Deep copy.b.c:", deep_copy_table.b.c)

额外示例:深拷贝的应用

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
-- 深拷贝的应用:配置对象的复制
local default_config = {
window = {
width = 800,
height = 600,
position = {x = 100, y = 100}
},
sound = {
volume = 0.7,
enabled = true
}
}

-- 创建用户配置,基于默认配置但有一些修改
local user_config = deep_copy(default_config)
user_config.window.width = 1024
user_config.window.height = 768
user_config.sound.volume = 0.9

print("Default window width:", default_config.window.width)
print("User window width:", user_config.window.width)
print("Default sound volume:", default_config.sound.volume)
print("User sound volume:", user_config.sound.volume)

9. 表的元表

元表(Metatable)是 Lua 中一个强大的特性,允许我们修改表的行为,例如定义运算符、访问控制等。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
local t1 = {1, 2, 3}
local t2 = {4, 5, 6}

-- 设置元表前,+操作会报错
-- print(t1 + t2) -- 错误:attempt to perform arithmetic on a table value

-- 创建元表
local mt = {
__add = function(a, b) -- 定义+操作
local result = {}
for _, v in ipairs(a) do table.insert(result, v) end
for _, v in ipairs(b) do table.insert(result, v) end
return result
end
}

-- 设置元表
setmetatable(t1, mt)
setmetatable(t2, mt)

-- 现在可以使用+操作符连接两个表
local t3 = t1 + t2
print("t1 + t2 =", table.concat(t3, ", "))

额外示例:更多元表操作

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
-- 定义更多元表操作
local mt = {
-- 算术运算符
__add = function(a, b) return a.value + b.value end,
__sub = function(a, b) return a.value - b.value end,

-- 关系运算符
__eq = function(a, b) return a.value == b.value end,
__lt = function(a, b) return a.value < b.value end,

-- 索引操作
__index = function(table, key)
if key == "double" then
return table.value * 2
end
return nil
end,

-- 新索引操作
__newindex = function(table, key, value)
if key == "value" and type(value) ~= "number" then
print("Error: value must be a number")
return
end
rawset(table, key, value)
end
}

-- 创建带有元表的表
local num1 = {value = 10}
local num2 = {value = 20}
setmetatable(num1, mt)
setmetatable(num2, mt)

print("num1 + num2 =", num1 + num2)
print("num2 - num1 =", num2 - num1)
print("num1 < num2 =", num1 < num2)
print("num1 == num2 =", num1 == num2)
print("num1.double =", num1.double)

-- 测试 __newindex
num1.value = 30
print("num1.value =", num1.value)
num1.value = "not a number" -- 应该报错
print("num1.value =", num1.value)

10. 额外内容:表的长度计算和特殊用法

表的长度计算

在 Lua 中,使用 # 操作符可以获取表的长度,但它只对序列(从 1 开始的连续数值索引)有效。

1
2
3
4
5
6
7
8
9
-- 表的长度计算
local seq = {1, 2, 3, 4, 5}
print("Length of sequence:", #seq) -- 正确:5

local sparse = {1, 2, nil, 4, 5}
print("Length of sparse table:", #sparse) -- 可能返回 2 或 5,取决于实现

local mixed = {1, 2, 3, name = "test", value = 100}
print("Length of mixed table:", #mixed) -- 只计算数组部分:3

表的特殊用法

表作为函数参数

表可以作为函数参数传递,这对于传递多个相关的值非常方便。

1
2
3
4
5
6
7
8
9
-- 表作为函数参数
function print_person(p)
print("Name:", p.name)
print("Age:", p.age)
print("City:", p.city)
end

local person = {name = "John", age = 30, city = "New York"}
print_person(person)

表作为函数返回值

函数可以返回表,这对于返回多个相关的值非常有用。

1
2
3
4
5
6
7
8
9
10
11
-- 表作为函数返回值
function create_person(name, age, city)
return {
name = name,
age = age,
city = city
}
end

local new_person = create_person("Alice", 25, "London")
print("New person:", new_person.name, new_person.age, new_person.city)

表作为模块

在 Lua 中,模块通常使用表来实现,将相关的函数和变量组织在一起。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
-- 表作为模块
local math_utils = {
pi = 3.14159,

add = function(a, b) return a + b end,
subtract = function(a, b) return a - b end,
multiply = function(a, b) return a * b end,
divide = function(a, b)
if b == 0 then return nil, "Division by zero" end
return a / b
end
}

print("math_utils.pi =", math_utils.pi)
print("math_utils.add(10, 5) =", math_utils.add(10, 5))
print("math_utils.divide(10, 2) =", math_utils.divide(10, 2))

运行示例

要运行 tables.lua 文件,只需在命令行中执行:

1
lua tables.lua

运行结果将显示各个部分的输出,包括表的基本操作、遍历、操作函数的使用等。

总结

本教程介绍了 Lua 编程语言中的表操作相关知识,包括:

  • 表的基本概念和创建方式
  • 数组(数值索引表)的使用
  • 字典(字符串索引表)的使用
  • 混合表的特性
  • 表的遍历方法(ipairs 和 pairs)
  • 表操作函数(insert, remove, sort, concat, unpack)
  • 嵌套表的应用
  • 表的浅拷贝和深拷贝
  • 表的元表和元方法
  • 表的长度计算和特殊用法

表是 Lua 中最强大、最灵活的数据结构,掌握表的使用对于 Lua 编程至关重要。通过本教程的学习,您应该已经对 Lua 表的各种操作有了全面的了解,可以在实际编程中灵活运用表来解决各种问题。

tables.lua

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
-- Lua表操作示例
-- print语句使用英语,注释使用中文

-- 1. 表的基本概念
print("=== Basic Concepts of Tables ===")

-- 空表
local empty_table = {}
print("Empty table:", empty_table)
print("Type of empty_table:", type(empty_table))

-- 2. 数组(数值索引表)
print("\n=== Arrays (Numeric Indexed Tables) ===")

-- 整数索引表,索引从1开始
local fruits = {"apple", "banana", "orange", "grape"}
print("Fruits table:")
print("First fruit:", fruits[1]) -- Lua数组索引从1开始
print("Second fruit:", fruits[2])
print("Number of fruits:", #fruits) -- #操作符获取表长度

-- 手动指定索引
local numbers = {[1] = 10, [2] = 20, [3] = 30}
print("Numbers table:", numbers[1], numbers[2], numbers[3])

-- 3. 字典(字符串索引表)
print("\n=== Dictionaries (String Indexed Tables) ===")

local person = {
name = "John",
age = 30,
city = "New York",
is_student = false
}

print("Person table:")
print("Name:", person.name) -- 点表示法
print("Age:", person["age"]) -- 方括号表示法

-- 添加新键值对
person.occupation = "Engineer"
person["salary"] = 50000
print("Occupation:", person.occupation)
print("Salary:", person.salary)

-- 删除键值对
person.is_student = nil
print("After deleting is_student:", person.is_student)

-- 4. 混合表(同时包含数组和字典部分)
print("\n=== Mixed Tables ===")

local mixed_table = {
"first", -- 索引1
"second", -- 索引2
name = "mixed",
value = 100,
"third" -- 索引3
}

print("Mixed table:")
print("Index 1:", mixed_table[1])
print("Index 2:", mixed_table[2])
print("Index 3:", mixed_table[3])
print("Name:", mixed_table.name)
print("Value:", mixed_table.value)
print("Length of mixed_table:", #mixed_table) -- 只计算数组部分

-- 5. 表遍历
print("\n=== Table Traversal ===")

-- 使用ipairs遍历数组部分(仅遍历数值索引,按顺序)
print("Using ipairs to iterate fruits:")
for index, fruit in ipairs(fruits) do
print("Index", index, ":", fruit)
end

-- 使用pairs遍历整个表(包括数组和字典部分,无序)
print("\nUsing pairs to iterate person:")
for key, value in pairs(person) do
print(key, ":", value)
end

-- 遍历混合表
print("\nUsing pairs to iterate mixed_table:")
for key, value in pairs(mixed_table) do
print(key, ":", value)
end

-- 6. 表操作函数
print("\n=== Table Operations ===")

-- table.insert:在指定位置插入元素
local numbers = {1, 2, 3, 4, 5}
print("Original numbers:", table.concat(numbers, ", "))

table.insert(numbers, 3, 100) -- 在索引3处插入100
print("After table.insert(numbers, 3, 100):", table.concat(numbers, ", "))

table.insert(numbers, 200) -- 在末尾插入200
print("After table.insert(numbers, 200):", table.concat(numbers, ", "))

-- table.remove:删除指定位置的元素
local removed = table.remove(numbers, 3) -- 删除索引3处的元素
print("Removed element:", removed)
print("After table.remove(numbers, 3):", table.concat(numbers, ", "))

removed = table.remove(numbers) -- 删除末尾元素
print("Removed element:", removed)
print("After table.remove(numbers):", table.concat(numbers, ", "))

-- table.sort:排序
local unsorted = {5, 2, 8, 1, 9, 3}
print("\nUnsorted:", table.concat(unsorted, ", "))

table.sort(unsorted)
print("Sorted ascending:", table.concat(unsorted, ", "))

-- 降序排序
table.sort(unsorted, function(a, b)
return a > b
end)
print("Sorted descending:", table.concat(unsorted, ", "))

-- table.concat:连接表元素为字符串
local words = {"Hello", "World", "Lua"}
local sentence = table.concat(words, " ")
print("\nConcatenated string:", sentence)

local numbers_str = table.concat({1, 2, 3, 4, 5}, "-")
print("Concatenated numbers:", numbers_str)

-- table.unpack:将表元素作为可变参数返回
local coords = {10, 20, 30}
local x, y, z = unpack(coords)
print("\nUnpacked coordinates:", x, y, z)

-- 7. 嵌套表
print("\n=== Nested Tables ===")

local matrix = {
{1, 2, 3},
{4, 5, 6},
{7, 8, 9}
}

print("Matrix:")
for i = 1, #matrix do
local row = matrix[i]
print(table.concat(row, "\t"))
end

-- 访问嵌套表元素
print("Element at (2, 3):", matrix[2][3])

-- 8. 表的深浅拷贝
print("\n=== Table Copying ===")

-- 浅拷贝示例
local original = {a = 1, b = {c = 2}}
local copy = {}
for key, value in pairs(original) do
copy[key] = value
end

print("Original.b.c:", original.b.c)
print("Copy.b.c:", copy.b.c)

-- 修改嵌套表,浅拷贝会影响原表
copy.b.c = 100
print("After modifying copy.b.c:")
print("Original.b.c:", original.b.c)
print("Copy.b.c:", copy.b.c)

-- 深拷贝函数
function deep_copy(orig)
local orig_type = type(orig)
local copy
if orig_type == 'table' then
copy = {}
for orig_key, orig_value in next, orig, nil do
copy[deep_copy(orig_key)] = deep_copy(orig_value)
end
setmetatable(copy, deep_copy(getmetatable(orig)))
else -- 基本类型直接复制
copy = orig
end
return copy
end

-- 使用深拷贝
local deep_copy_table = deep_copy(original)
deep_copy_table.b.c = 200
print("\nAfter deep copy and modifying:")
print("Original.b.c:", original.b.c)
print("Deep copy.b.c:", deep_copy_table.b.c)

-- 9. 表的元表(简单示例)
print("\n=== Metatables (Simple Example) ===")

local t1 = {1, 2, 3}
local t2 = {4, 5, 6}

-- 设置元表前,+操作会报错
-- print(t1 + t2) -- 错误:attempt to perform arithmetic on a table value

-- 创建元表
local mt = {
__add = function(a, b) -- 定义+操作
local result = {}
for _, v in ipairs(a) do table.insert(result, v) end
for _, v in ipairs(b) do table.insert(result, v) end
return result
end
}

-- 设置元表
setmetatable(t1, mt)
setmetatable(t2, mt)

-- 现在可以使用+操作符连接两个表
local t3 = t1 + t2
print("t1 + t2 =", table.concat(t3, ", "))

Lua 函数教程

本教程基于 functions.lua 文件,详细介绍 Lua 编程语言中的函数相关知识。

目录

  1. 基本函数定义和调用
  2. 匿名函数
  3. 闭包
  4. 可变参数函数
  5. 函数返回多个值
  6. 尾调用优化
  7. 函数作为表成员
  8. 词法作用域
  9. 额外内容:函数重载和默认参数

1. 基本函数定义和调用

标准函数定义

在 Lua 中,可以使用 function 关键字定义函数。

1
2
3
4
5
6
7
-- 标准函数定义
function add(a, b)
return a + b
end

local sum = add(10, 20)
print("add(10, 20) =", sum)

函数赋值给变量

函数可以作为值赋给变量,这使得函数可以像其他类型的值一样处理。

1
2
3
4
5
6
7
-- 函数赋值给变量
local multiply = function(a, b)
return a * b
end

local product = multiply(5, 6)
print("multiply(5, 6) =", product)

额外示例:函数作为参数传递

函数可以作为参数传递给其他函数,这是 Lua 函数式编程的重要特性。

1
2
3
4
5
6
7
8
9
10
-- 函数作为参数传递
function apply_operation(a, b, operation)
return operation(a, b)
end

local result1 = apply_operation(10, 5, add)
print("apply_operation(10, 5, add) =", result1)

local result2 = apply_operation(10, 5, function(x, y) return x - y end)
print("apply_operation(10, 5, subtract) =", result2)

2. 匿名函数

匿名函数是没有名称的函数,通常用于简短的操作或作为参数传递给其他函数。

1
2
3
4
5
6
7
8
9
10
11
12
-- 作为参数传递给其他函数
local numbers = {1, 2, 3, 4, 5}

-- 使用匿名函数对表进行排序(降序)
table.sort(numbers, function(a, b)
return a > b
end)

print("Sorted in descending order:")
for _, num in ipairs(numbers) do
print(num)
end

额外示例:使用匿名函数进行表过滤

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
-- 使用匿名函数过滤表中的元素
function filter_table(tbl, condition)
local result = {}
for _, value in ipairs(tbl) do
if condition(value) then
table.insert(result, value)
end
end
return result
end

local numbers = {1, 2, 3, 4, 5, 6, 7, 8, 9, 10}
local even_numbers = filter_table(numbers, function(x) return x % 2 == 0 end)
print("Even numbers:")
for _, num in ipairs(even_numbers) do
print(num)
end

3. 闭包

闭包是一个函数加上它可以访问的外部变量(也称为上值)。闭包可以捕获和保持其创建环境中的变量。

计数器示例

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
-- 闭包函数,返回一个递增计数器
function create_counter(initial)
local count = initial or 0

-- 内部函数可以访问外部函数的局部变量
return function()
count = count + 1
return count
end
end

-- 创建两个计数器实例
local counter1 = create_counter()
local counter2 = create_counter(100)

print("counter1:", counter1())
print("counter1:", counter1())
print("counter2:", counter2())
print("counter1:", counter1())
print("counter2:", counter2())

乘法器示例

1
2
3
4
5
6
7
8
9
10
11
12
-- 另一个闭包示例:生成乘法器
function create_multiplier(factor)
return function(num)
return num * factor
end
end

local double = create_multiplier(2)
local triple = create_multiplier(3)

print("double(5) =", double(5))
print("triple(5) =", triple(5))

额外示例:带有状态的闭包

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
-- 带有状态的闭包:简单的栈实现
function create_stack()
local stack = {}

return {
push = function(value)
table.insert(stack, value)
end,
pop = function()
return table.remove(stack)
end,
size = function()
return #stack
end
}
end

local my_stack = create_stack()
my_stack.push(10)
my_stack.push(20)
my_stack.push(30)
print("Stack size:", my_stack.size())
print("Pop:", my_stack.pop())
print("Stack size after pop:", my_stack.size())

4. 可变参数函数

Lua 支持可变参数函数,即函数可以接受任意数量的参数。使用 ... 表示可变参数。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
-- 使用...表示可变参数
function average(...)
local sum = 0
local count = 0

-- 使用arg获取可变参数(Lua 5.1)或使用...直接迭代(Lua 5.2+)
for _, num in ipairs({...}) do
sum = sum + num
count = count + 1
end

if count == 0 then
return 0
end

return sum / count
end

print("average(1, 2, 3, 4, 5) =", average(1, 2, 3, 4, 5))
print("average(10, 20) =", average(10, 20))
print("average() =", average())

额外示例:处理可变参数的不同方式

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
-- 另一种处理可变参数的方式
function concatenate(...)
local result = ""
for _, str in ipairs({...}) do
result = result .. str
end
return result
end

print("concatenate('Hello', ' ', 'Lua', '!') =", concatenate('Hello', ' ', 'Lua', '!'))

-- 混合固定参数和可变参数
function mixed_args(first, ...)
print("First argument:", first)
print("Remaining arguments:")
for i, arg in ipairs({...}) do
print(i, arg)
end
end

mixed_args("Hello", "World", "Lua", "Programming")

5. 函数返回多个值

Lua 函数可以返回多个值,这是 Lua 的一个重要特性。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
function get_min_max(...) 
local args = {...}
if #args == 0 then
return nil, nil
end

local min_val = args[1]
local max_val = args[1]

for i = 2, #args do
if args[i] < min_val then
min_val = args[i]
end
if args[i] > max_val then
max_val = args[i]
end
end

return min_val, max_val
end

local min, max = get_min_max(5, 2, 9, 1, 7)
print("min and max of {5, 2, 9, 1, 7}:", min, max)

额外示例:返回多个值的应用

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
-- 返回多个值的应用:分解表
function unpack_table(tbl)
return tbl[1], tbl[2], tbl[3]
end

local my_table = {10, 20, 30}
local a, b, c = unpack_table(my_table)
print("Unpacked table:", a, b, c)

-- 返回状态和结果
function divide(a, b)
if b == 0 then
return false, "Division by zero"
end
return true, a / b
end

local success, result = divide(10, 2)
if success then
print("Division result:", result)
else
print("Error:", result)
end

6. 尾调用优化

尾调用是指函数的最后一个操作是调用另一个函数,而不是对调用结果进行任何操作。Lua 会对尾调用进行优化,避免栈溢出。

1
2
3
4
5
6
7
8
9
10
11
-- 尾递归函数:计算阶乘
function factorial_tail(n, acc)
acc = acc or 1
if n <= 1 then
return acc
end
-- 尾调用:函数调用是最后一个操作
return factorial_tail(n - 1, n * acc)
end

print("factorial_tail(5) =", factorial_tail(5))

额外示例:非尾递归 vs 尾递归

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
-- 非尾递归版本(可能导致栈溢出)
function factorial_regular(n)
if n <= 1 then
return 1
end
-- 非尾调用:需要对结果进行乘法操作
return n * factorial_regular(n - 1)
end

print("factorial_regular(5) =", factorial_regular(5))

-- 尾递归版本(不会导致栈溢出)
function factorial_tail(n, acc)
acc = acc or 1
if n <= 1 then
return acc
end
-- 尾调用:函数调用是最后一个操作
return factorial_tail(n - 1, n * acc)
end

print("factorial_tail(5) =", factorial_tail(5))

7. 函数作为表成员

在 Lua 中,函数可以作为表的成员,这是实现面向对象编程的基础。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
local math_operations = {
add = function(a, b) return a + b end,
subtract = function(a, b) return a - b end,
multiply = function(a, b) return a * b end,
divide = function(a, b)
if b == 0 then
return nil, "Division by zero"
end
return a / b
end
}

print("math_operations.add(10, 5) =", math_operations.add(10, 5))
print("math_operations.subtract(10, 5) =", math_operations.subtract(10, 5))
print("math_operations.multiply(10, 5) =", math_operations.multiply(10, 5))

local result, error_msg = math_operations.divide(10, 0)
if result then
print("math_operations.divide(10, 0) =", result)
else
print("Error:", error_msg)
end

额外示例:使用冒号语法定义表方法

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
-- 使用冒号语法定义表方法
local person = {
name = "John",
age = 30,

-- 使用冒号语法定义方法,会自动传入self参数
greet = function(self)
print("Hello, my name is " .. self.name)
end,

-- 另一种使用冒号语法的方式
celebrate_birthday = function(self)
self.age = self.age + 1
print("Happy birthday! I'm now " .. self.age .. " years old.")
end
}

-- 使用冒号调用方法,会自动传入表作为self参数
person:greet()
person:celebrate_birthday()

8. 词法作用域

Lua 使用词法作用域,即变量的作用域由其在代码中的位置决定,而不是由其执行位置决定。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
local outer_var = "outside"

function outer_function()
local inner_var = "inside"

function inner_function()
-- 可以访问外部函数的变量和全局变量
print("inner_var:", inner_var)
print("outer_var:", outer_var)
end

return inner_function
end

local inner = outer_function()
inner()

额外示例:词法作用域的应用

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
-- 词法作用域的应用:创建私有变量
function create_person(name)
local age = 0 -- 私有变量,外部无法直接访问

return {
get_name = function()
return name
end,

get_age = function()
return age
end,

set_age = function(new_age)
if new_age > 0 then
age = new_age
return true
end
return false
end
}
end

local person = create_person("Alice")
print("Name:", person.get_name())
print("Age:", person.get_age())
person.set_age(25)
print("Age after update:", person.get_age())

9. 额外内容:函数重载和默认参数

函数重载

Lua 不直接支持函数重载,但可以通过检查参数类型和数量来模拟函数重载。

1
2
3
4
5
6
7
8
9
10
11
12
13
-- 模拟函数重载
function calculate(a, b)
if type(a) == "number" and type(b) == "number" then
return a + b
elseif type(a) == "string" and type(b) == "string" then
return a .. b
else
return nil, "Invalid arguments"
end
end

print("calculate(1, 2) =", calculate(1, 2))
print("calculate('Hello', ' Lua') =", calculate('Hello', ' Lua'))

默认参数

Lua 不直接支持默认参数,但可以通过检查参数是否为 nil 来实现类似功能。

1
2
3
4
5
6
7
8
9
10
-- 实现默认参数
function greet(name, greeting)
name = name or "Guest"
greeting = greeting or "Hello"
print(greeting .. ", " .. name .. "!")
end

greet("John") -- 使用默认问候语
greet("Jane", "Hi") -- 使用自定义问候语
greet() -- 使用默认名称和问候语

运行示例

要运行 functions.lua 文件,只需在命令行中执行:

1
lua functions.lua

运行结果将显示各个部分的输出,包括函数调用结果、闭包示例、可变参数处理等。

总结

本教程介绍了 Lua 编程语言中的函数相关知识,包括:

  • 基本函数定义和调用
  • 匿名函数
  • 闭包
  • 可变参数函数
  • 函数返回多个值
  • 尾调用优化
  • 函数作为表成员
  • 词法作用域
  • 函数重载和默认参数的模拟实现

通过学习这些知识,您已经掌握了 Lua 函数的核心概念和高级特性,可以编写更加灵活、高效的 Lua 代码。

functions.lua

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
-- Lua函数示例
-- print语句使用英语,注释使用中文

-- 1. 基本函数定义和调用
print("=== Basic Function Definition and Call ===")

-- 标准函数定义
function add(a, b)
return a + b
end

local sum = add(10, 20)
print("add(10, 20) =", sum)

-- 函数赋值给变量
local multiply = function(a, b)
return a * b
end

local product = multiply(5, 6)
print("multiply(5, 6) =", product)

-- 2. 匿名函数
print("\n=== Anonymous Functions ===")

-- 作为参数传递给其他函数
local numbers = {1, 2, 3, 4, 5}

-- 使用匿名函数对表进行排序(降序)
table.sort(numbers, function(a, b)
return a > b
end)

print("Sorted in descending order:")
for _, num in ipairs(numbers) do
print(num)
end

-- 3. 闭包
print("\n=== Closures ===")

-- 闭包函数,返回一个递增计数器
function create_counter(initial)
local count = initial or 0

-- 内部函数可以访问外部函数的局部变量
return function()
count = count + 1
return count
end
end

-- 创建两个计数器实例
local counter1 = create_counter()
local counter2 = create_counter(100)

print("counter1:", counter1())
print("counter1:", counter1())
print("counter2:", counter2())
print("counter1:", counter1())
print("counter2:", counter2())

-- 另一个闭包示例:生成乘法器
function create_multiplier(factor)
return function(num)
return num * factor
end
end

local double = create_multiplier(2)
local triple = create_multiplier(3)

print("double(5) =", double(5))
print("triple(5) =", triple(5))

-- 4. 可变参数函数
print("\n=== Variadic Functions ===")

-- 使用...表示可变参数
function average(...)
local sum = 0
local count = 0

-- 使用arg获取可变参数(Lua 5.1)或使用...直接迭代(Lua 5.2+)
for _, num in ipairs({...}) do
sum = sum + num
count = count + 1
end

if count == 0 then
return 0
end

return sum / count
end

print("average(1, 2, 3, 4, 5) =", average(1, 2, 3, 4, 5))
print("average(10, 20) =", average(10, 20))
print("average() =", average())

-- 5. 函数返回多个值
print("\n=== Functions Returning Multiple Values ===")

function get_min_max(...)
local args = {...}
if #args == 0 then
return nil, nil
end

local min_val = args[1]
local max_val = args[1]

for i = 2, #args do
if args[i] < min_val then
min_val = args[i]
end
if args[i] > max_val then
max_val = args[i]
end
end

return min_val, max_val
end

local min, max = get_min_max(5, 2, 9, 1, 7)
print("min and max of {5, 2, 9, 1, 7}:", min, max)

-- 6. 尾调用优化
print("\n=== Tail Call Optimization ===")

-- 尾递归函数:计算阶乘
function factorial_tail(n, acc)
acc = acc or 1
if n <= 1 then
return acc
end
-- 尾调用:函数调用是最后一个操作
return factorial_tail(n - 1, n * acc)
end

print("factorial_tail(5) =", factorial_tail(5))

-- 7. 函数作为表成员
print("\n=== Functions as Table Members ===")

local math_operations = {
add = function(a, b) return a + b end,
subtract = function(a, b) return a - b end,
multiply = function(a, b) return a * b end,
divide = function(a, b)
if b == 0 then
return nil, "Division by zero"
end
return a / b
end
}

print("math_operations.add(10, 5) =", math_operations.add(10, 5))
print("math_operations.subtract(10, 5) =", math_operations.subtract(10, 5))
print("math_operations.multiply(10, 5) =", math_operations.multiply(10, 5))

local result, error_msg = math_operations.divide(10, 0)
if result then
print("math_operations.divide(10, 0) =", result)
else
print("Error:", error_msg)
end

-- 8. 词法作用域
print("\n=== Lexical Scoping ===")

local outer_var = "outside"

function outer_function()
local inner_var = "inside"

function inner_function()
-- 可以访问外部函数的变量和全局变量
print("inner_var:", inner_var)
print("outer_var:", outer_var)
end

return inner_function
end

local inner = outer_function()
inner()

Lua 基础语法教程

本教程基于 basics.lua 文件,详细介绍 Lua 编程语言的基础语法知识。

目录

  1. 变量声明和赋值
  2. 数据类型
  3. 条件语句
  4. 循环结构
  5. 运算符

1. 变量声明和赋值

全局变量

在 Lua 中,不使用 local 关键字声明的变量是全局变量。

1
2
3
-- 全局变量
global_var = 10 -- 不使用local声明的是全局变量
print("Global variable:", global_var)

局部变量

使用 local 关键字声明的变量是局部变量,其作用域仅限于声明它的块。

1
2
3
-- 局部变量
local local_var = 20 -- 使用local声明的是局部变量
print("Local variable:", local_var)

多重赋值

Lua 支持同时给多个变量赋值。

1
2
3
-- 多重赋值
local a, b, c = 1, 2, 3
print("Multiple assignment:", a, b, c)

交换变量值

利用多重赋值的特性,可以方便地交换变量值。

1
2
3
4
5
-- 交换变量值
local x, y = 10, 20
print("Before swap:", x, y)
x, y = y, x
print("After swap:", x, y)

额外示例:变量的默认值

当赋值表达式的数量少于变量数量时,多余的变量会被赋予 nil 值。

1
2
3
-- 变量的默认值
local p, q, r = 1, 2
print("p:", p, "q:", q, "r:", r) -- r 会被赋值为 nil

2. 数据类型

Lua 是一种动态类型语言,共有 8 种基本数据类型:nil、boolean、number、string、table、function、userdata 和 thread。

nil 类型

nil 是一个特殊的值,表示”无”或”不存在”。

1
2
3
-- nil类型
local nil_var = nil
print("nil type:", type(nil_var))

boolean 类型

布尔类型只有两个值:truefalse

1
2
3
4
-- boolean类型
local bool_true = true
local bool_false = false
print("boolean type:", type(bool_true), type(bool_false))

number 类型

Lua 中只有一种数值类型,用于表示整数和浮点数。

1
2
3
4
5
-- number类型(Lua中只有一种数值类型)
local int_num = 42
local float_num = 3.14
local exp_num = 1e-3
print("number type:", type(int_num), type(float_num), type(exp_num))

string 类型

字符串是由零个或多个字符组成的序列,可以用单引号、双引号或长字符串语法([[...]])表示。

1
2
3
4
5
6
7
-- string类型
local str1 = "Hello"
local str2 = 'World'
local str3 = [[Multi-line
string]]
print("string type:", type(str1), str1, str2)
print("Multi-line string:", str3)

table 类型

表是 Lua 中唯一的复合数据类型,可以用来表示数组、字典等数据结构。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
-- table类型(Lua中唯一的复合数据类型)
local tbl = {1, 2, 3}
print("table type:", type(tbl))

-- 表作为数组
local arr = {10, 20, 30, 40, 50}
print("Array elements:")
for i = 1, #arr do
print(i, arr[i])
end

-- 表作为字典
local dict = {name = "John", age = 30, city = "New York"}
print("Dictionary elements:")
for key, value in pairs(dict) do
print(key, value)
end

function 类型

函数是 Lua 中的第一类值,可以存储在变量中、作为参数传递或作为返回值。

1
2
3
4
5
6
7
8
9
10
-- function类型
local func = function() print("Hello") end
print("function type:", type(func))
func() -- 调用函数

-- 命名函数
function greet(name)
print("Hello, " .. name .. "!")
end
greet("Lua")

userdata 和 thread 类型

  • userdata:用于表示由 C 语言创建的自定义类型。
  • thread:用于表示协程(coroutine)。

3. 条件语句

Lua 提供了 ifelseifelse 语句来实现条件判断。

if-else 语句

1
2
3
4
5
6
7
8
9
-- if-else语句
local num = 10
if num > 0 then
print("Positive number")
elseif num < 0 then
print("Negative number")
else
print("Zero")
end

额外示例:嵌套的条件语句

1
2
3
4
5
6
7
8
9
10
11
-- 嵌套的条件语句
local score = 85
if score >= 90 then
print("Excellent!")
elseif score >= 70 then
print("Good job!")
elseif score >= 60 then
print("Pass.")
else
print("Need to improve.")
end

4. 循环结构

Lua 提供了三种循环结构:forwhilerepeat-until

for 循环(数值型)

用于执行固定次数的循环。

1
2
3
4
5
-- for循环(数值型)
print("Numeric for loop:")
for i = 1, 5 do
print(i)
end

for 循环(带步长)

可以指定循环的步长。

1
2
3
4
5
-- for循环(带步长)
print("\nNumeric for loop with step:")
for i = 5, 1, -1 do
print(i)
end

while 循环

在条件为真时重复执行循环体。

1
2
3
4
5
6
7
-- while循环
print("\nWhile loop:")
local count = 1
while count <= 5 do
print(count)
count = count + 1
end

repeat-until 循环

至少执行一次循环体,然后在条件为真时停止。

1
2
3
4
5
6
7
-- repeat-until循环(至少执行一次)
print("\nRepeat-until loop:")
local i = 1
repeat
print(i)
i = i + 1
until i > 5

额外示例:泛型 for 循环

用于遍历表中的元素。

1
2
3
4
5
6
7
8
9
10
11
12
-- 泛型for循环遍历表
print("\nGeneric for loop:")
local fruits = {"apple", "banana", "orange"}
for index, value in ipairs(fruits) do
print(index, value)
end

-- 泛型for循环遍历字典
local person = {name = "Alice", age = 25, job = "Engineer"}
for key, value in pairs(person) do
print(key, value)
end

5. 运算符

算术运算符

1
2
3
4
5
6
7
8
9
-- 算术运算符
local a, b = 10, 3
print("Arithmetic operators:")
print("a + b =", a + b) -- 加法
print("a - b =", a - b) -- 减法
print("a * b =", a * b) -- 乘法
print("a / b =", a / b) -- 除法(浮点数)
print("a % b =", a % b) -- 取模
print("a ^ b =", a ^ b) -- 幂运算

关系运算符

1
2
3
4
5
6
7
8
-- 关系运算符
print("\nRelational operators:")
print("a == b", a == b) -- 等于
print("a ~= b", a ~= b) -- 不等于
print("a > b", a > b) -- 大于
print("a < b", a < b) -- 小于
print("a >= b", a >= b) -- 大于等于
print("a <= b", a <= b) -- 小于等于

逻辑运算符

1
2
3
4
5
6
-- 逻辑运算符
print("\nLogical operators:")
local x, y = true, false
print("x and y", x and y) -- 逻辑与
print("x or y", x or y) -- 逻辑或
print("not x", not x) -- 逻辑非

字符串连接运算符

1
2
3
4
-- 字符串连接运算符
print("\nString concatenation:")
local str1, str2 = "Hello", "World"
print("str1 .. str2 =", str1 .. " " .. str2) -- 使用 .. 连接字符串

额外示例:运算符优先级

Lua 中的运算符优先级从高到低依次为:

  1. ^
  2. 一元运算符(not, #, -)
  3. *, /, %
  4. +, -
  5. ..
  6. <, >, <=, >=, ~=, ==
  7. and
  8. or
1
2
3
4
5
6
-- 运算符优先级示例
local result = 2 + 3 * 4
print("2 + 3 * 4 =", result) -- 结果为 14,因为 * 优先级高于 +

local result2 = (2 + 3) * 4
print("(2 + 3) * 4 =", result2) -- 结果为 20,使用括号改变优先级

运行示例

要运行 basics.lua 文件,只需在命令行中执行:

1
lua basics.lua

运行结果将显示各个部分的输出,包括变量值、数据类型信息、条件判断结果、循环执行过程和运算符计算结果。

总结

本教程介绍了 Lua 编程语言的基础语法,包括:

  • 变量声明和赋值
  • 数据类型
  • 条件语句
  • 循环结构
  • 运算符

通过学习这些基础知识,您已经为进一步学习 Lua 的高级特性(如函数闭包、表操作、模块系统等)打下了坚实的基础。

basics.lua

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
-- Lua基础语法示例
-- print语句使用英语,注释使用中文

-- 1. Variable Declaration and Assignment
print("=== Variable Declaration and Assignment ===")
-- 全局变量
local_var = 10 -- 不使用local声明的是全局变量
print("Global variable:", local_var)

-- 局部变量
local local_var = 20 -- 使用local声明的是局部变量
print("Local variable:", local_var)

-- 多重赋值
local a, b, c = 1, 2, 3
print("Multiple assignment:", a, b, c)

-- 交换变量值
local x, y = 10, 20
a, b = b, a
print("After swap:", a, b)

-- 2. Data Types
print("\n=== Data Types ===")
-- nil类型
local nil_var = nil
print("nil type:", type(nil_var))

-- boolean类型
local bool_true = true
local bool_false = false
print("boolean type:", type(bool_true), type(bool_false))

-- number类型(Lua中只有一种数值类型)
local int_num = 42
local float_num = 3.14
local exp_num = 1e-3
print("number type:", type(int_num), type(float_num), type(exp_num))

-- string类型
local str1 = "Hello"
local str2 = 'World'
local str3 = [[Multi-line
string]]
print("string type:", type(str1), str1, str2)
print("Multi-line string:", str3)

-- table类型(Lua中唯一的复合数据类型)
local tbl = {1, 2, 3}
print("table type:", type(tbl))

-- function类型
local func = function() print("Hello") end
print("function type:", type(func))

-- 3. Conditional Statements
print("\n=== Conditional Statements ===")
local num = 10

-- if-else语句
if num > 0 then
print("Positive number")
elseif num < 0 then
print("Negative number")
else
print("Zero")
end

-- 4. Loop Structures
print("\n=== Loop Structures ===")

-- for循环(数值型)
print("Numeric for loop:")
for i = 1, 5 do
print(i)
end

-- for循环(带步长)
print("\nNumeric for loop with step:")
for i = 5, 1, -1 do
print(i)
end

-- while循环
print("\nWhile loop:")
local count = 1
while count <= 5 do
print(count)
count = count + 1
end

-- repeat-until循环(至少执行一次)
print("\nRepeat-until loop:")
local i = 1
repeat
print(i)
i = i + 1
until i > 5

-- 5. Operators
print("\n=== Operators ===")

-- 算术运算符
local a, b = 10, 3
print("Arithmetic operators:")
print("a + b =", a + b)
print("a - b =", a - b)
print("a * b =", a * b)
print("a / b =", a / b)
print("a % b =", a % b)
print("a ^ b =", a ^ b)

-- 关系运算符
print("\nRelational operators:")
print("a == b", a == b)
print("a ~= b", a ~= b)
print("a > b", a > b)
print("a < b", a < b)
print("a >= b", a >= b)
print("a <= b", a <= b)

-- 逻辑运算符
print("\nLogical operators:")
local x, y = true, false
print("x and y", x and y)
print("x or y", x or y)
print("not x", not x)

-- 字符串连接运算符
print("\nString concatenation:")
local str1, str2 = "Hello", "World"
print("str1 .. str2 =", str1 .. " " .. str2)

安装 hexo 主题 landscape

Landscape

NPM version

一个全新的 Hexo 默认主题。

安装

安装主题

如果您使用的是 Hexo 5.0 或更高版本,最简单的安装方式是通过 npm:

1
npm i hexo-theme-landscape

通过 git 安装:

1
git clone --depth 1 https://github.com/hexojs/hexo-theme-landscape themes/landscape

如果您想启用 RSS 功能,还需要安装 hexo-generator-feed 插件。

启用主题

修改 _config.yml 中的 theme 设置为 landscape

1
2
3
_config.yml
- theme: some-theme
+ theme: landscape

更新主题

通过 npm 安装最新版本:

1
npm install hexo-theme-landscape@latest

或者通过 git 更新到最新的 master 分支:

1
2
cd themes/landscape
git pull

配置

主题的配置文件是仓库中的 _config.yml。作为 Hexo 的默认主题,hexo-theme-landscape 在 hexo init 创建站点过程中通过 npm 安装,因此它通常位于 node_modules/hexo-theme-landscape 目录中。如果您通过 git clone 或其他方式安装,它可能位于 themes/landscape 目录中。

需要注意的是,为了防止您对主题配置文件的修改在主题升级过程中丢失或被覆盖,我们不建议直接修改这个默认配置文件。您可以将主题的 _config.yml 复制到您的博客根目录,命名为 _config.landscape.yml,并根据其中的配置选项文档进行配置(请参阅 替代主题配置)。

下面也将详细介绍一些选项的用法。

特性

FancyBox

Landscape 使用 Fancybox 来展示您的照片。您可以使用 Markdown 语法或 fancybox 标签插件来添加照片。

1
2
3
![img caption](img url)

{% fancybox img_url [img_thumbnail] [img_caption] %}

侧边栏

您可以通过编辑 sidebar 设置,将侧边栏放在站点的左侧、右侧或底部。

Landscape 提供了 5 个内置小部件:

  • category(分类)
  • tag(标签)
  • tagcloud(标签云)
  • archives(归档)
  • recent_posts(最近文章)

默认情况下,所有小部件都已启用。您可以在 widget 设置中编辑它们。

头部链接

您可以添加带有图标的链接到头部区域。

1
2
3
4
links:
github: https://github.com/your_github_account
twitter: https://twitter.com/your_twitter_account
telegram: https://t.me/your_telegram_account

安装 hexo 主题 light

Light

一个适用于 Hexo 的简约主题。

安装

执行以下命令,并将 _config.yml 中的 theme 修改为 light

1
git clone --depth 1 https://github.com/hexojs/hexo-theme-light themes/light
1
2
3
_config.yml
- theme: some-theme
+ theme: light

更新

执行以下命令来更新 Light 主题。

1
2
cd themes/light
git pull

配置

默认配置:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
menu:
Home: /
Archives: /archives

widgets:
- search
- category
- tag
- twitter

excerpt_link: Read More

twitter:
username:
show_replies: false
tweet_count: 5

fancybox: true

google_analytics:
rss:
  • menu - 主导航菜单
  • widget - 侧边栏显示的小部件
  • excerpt_link - 摘要文章底部的”阅读更多”链接文本
  • twitter - Twitter 小部件配置
    • username - Twitter 用户名
    • show_replies - 启用显示回复
    • tweet_count - 小部件中显示的推文数量
  • fancybox - 启用 Fancybox
  • google_analytics - Google Analytics ID
  • rss - RSS 订阅链接(如果使用 Feedburner 请修改)

特性

图库文章

Gallery Post

链接文章

Link Post

Twitter 小部件

Tweet Widget

Fancybox

Fancybox

Hexo Hello World

欢迎使用 Hexo!这是你的第一篇文章。查看 文档 了解更多信息。如果你在使用 Hexo 时遇到任何问题,可以在 故障排除 中找到答案,或者在 GitHub 上向我提问。

快速开始

创建新文章

1
$ hexo new "My New Post"

更多信息:写作

运行服务器

1
$ hexo server

更多信息:服务器

生成静态文件

1
$ hexo generate

更多信息:生成

部署到远程站点

1
$ hexo deploy

更多信息:部署