第二章:数据类型与值

在 Lua 中,值(Value)是一等公民,而变量本身没有类型,只有值才有类型。这意味着你可以将任何类型的值赋给任何变量。Lua 是一种动态类型语言,这为编程带来了极大的灵活性。

本章将详细介绍 Lua 的 8 种基本数据类型,并深入探讨字符串和表(Table)的基础用法。

2.1 基本数据类型

Lua 包含以下 8 种基本数据类型:

类型 描述
nil 空值,表示无效值。
boolean 布尔值,包含 truefalse
number 数字,Lua 5.3+ 支持整数和浮点数。
string 字符串,字符序列。
function 函数,由 C 或 Lua 编写。
userdata 用户数据,用于存储 C 数据结构。
thread 线程,用于协程(Coroutine)。
table 表,Lua 中唯一的数据结构。

我们可以使用 type() 函数来检查值的类型:

print(type("Hello"))  -- string
print(type(10))       -- number
print(type(print))    -- function
print(type(nil))      -- nil
print(type(true))     -- boolean

nil (空)

nil 是一种特殊的类型,它只有一个值 nil。它主要用来表示“无值”或“无效值”。全局变量在第一次赋值前默认值为 nil。将全局变量赋值为 nil 相当于删除了该变量。

boolean (布尔)

布尔类型有两个值:truefalse
重要提示:在 Lua 中,除了 falsenil 视为假(false),其他所有值都视为真(true)。这意味着数字 0 和空字符串 "" 在 Lua 中都被视为 true

number (数字)

Lua 5.3 引入了整数(integer)和浮点数(float)的区分。

  • 整数:64 位有符号整数。

  • 浮点数:双精度浮点数(符合 IEEE 754 标准)。

通常情况下,你不需要关心它是整数还是浮点数,Lua 会自动处理。

a = 10      -- 整数
b = 10.5    -- 浮点数
c = 1e-3    -- 科学计数法 0.001

string (字符串)

字符串是不可变的字节序列。你可以使用单引号 ' 或双引号 " 来界定字符串。

s1 = "Hello"
s2 = 'World'

还可以使用 [[...]] 来表示多行字符串,这种方式不会解释转义序列:

html = [[
<html>
<head></head>
<body>
    <a href="http://www.lua.org">Lua</a>
</body>
</html>
]]

table (表)

表是 Lua 中最强大且唯一的数据结构。它可以用来实现数组、字典、集合、队列、类、模块等。我们将在 2.3 节详细介绍。

function (函数)

函数是第一类值(First-class values),这意味着函数可以像数字或字符串一样存储在变量中、作为参数传递给其他函数,或者作为返回值返回。

userdata (用户数据)

userdata 允许将 C 语言的数据结构存储在 Lua 变量中。这通常用于 Lua 与 C 的交互,在纯 Lua 脚本中无法创建 userdata

thread (线程)

thread 类型用于实现协程(Coroutine),这与操作系统线程不同,协程是协作式的多任务处理。

2.2 字符串详解

字符串的创建与表示

如上所述,可以使用单引号、双引号或长括号创建字符串。

字符串连接

使用 .. 运算符连接两个字符串。如果操作数是数字,Lua 会自动将其转换为字符串。

print("Hello " .. "World")  -- Hello World
print(10 .. 20)             -- 1020 (注意数字后留空格,防止被解析为小数点)

字符串长度

使用 # 运算符获取字符串的长度(字节数)。

s = "Hello"
print(#s)  -- 5

字符串操作

Lua 的 string 库提供了丰富的字符串操作函数。

  • string.upper(s): 转大写

  • string.lower(s): 转小写

  • string.reverse(s): 字符串反转

  • string.format(fmt, …): 格式化字符串,类似于 C 语言的 printf

s = "Lua"
print(string.upper(s))               -- LUA
print(string.format("Hi %s", s))     -- Hi Lua
print(string.format("Date: %02d/%02d", 1, 2)) -- Date: 01/02

类型转换

  • tonumber(str): 将字符串转换为数字,如果转换失败返回 nil

  • tostring(num): 将数字转换为字符串。

print(tonumber("123") + 1)  -- 124
print(tonumber("abc"))      -- nil
print(tostring(100) == "100") -- true

2.3 表(Table)基础

表是 Lua 的核心。它本质上是一个关联数组(Associative Array),索引可以是除 nil 以外的任何值。

表的创建与初始化

使用 {} 创建一个空表。

t = {}
t["key"] = "value"
print(t["key"])  -- value

数组风格的表

Lua 中的数组通常以 1 作为起始索引(不同于大多数语言的 0)。

days = {"Sunday", "Monday", "Tuesday", "Wednesday", "Thursday", "Friday", "Saturday"}
print(days[1])  -- Sunday

字典风格的表

你可以像操作对象属性一样操作表。

user = {
    name = "Alice",
    age = 30,
    job = "Engineer"
}

print(user.name)  -- Alice
print(user["age"]) -- 30

user.name 实际上是 user["name"] 的语法糖。

表的遍历

使用 pairs 遍历字典(键值对),使用 ipairs 遍历数组(数值索引)。

-- 遍历数组
t = {10, 20, 30}
for i, v in ipairs(t) do
    print(i, v)
end
-- 输出:
-- 1	10
-- 2	20
-- 3	30

-- 遍历字典
config = {host = "localhost", port = 8080}
for k, v in pairs(config) do
    print(k, v)
end
-- 输出 (顺序不保证):
-- host	localhost
-- port	8080

练习题

  1. 定义一个字符串变量,包含你的名字。使用 string.reverse 将其反转并打印。

  2. 创建一个表,存储你喜欢的 3 种水果名称。使用 ipairs 遍历并打印它们。

  3. 创建一个表来描述一本图书,包含 title(标题)、author(作者)和 price(价格)。尝试修改价格并打印新的信息。

  4. 编写代码验证:Lua 中的 0true 还是 false


下一章预告:我们将学习 Lua 的流程控制语句,包括条件判断和各种循环结构,让你的程序具备逻辑处理能力。