六种基本数据类型详解
1. nil (空值)
nil 类型只有一个值,就是 nil。它代表一个无效或不存在的值。
- 默认值 :一个全局变量在首次被赋值前,其默认值就是
nil。 - 删除变量 :将一个变量赋值为
nil,相当于删除这个变量。 - 逻辑假 :在条件判断中,
nil被视为"假"。
2. boolean (布尔值)
boolean 类型只有两个值:true 和 false。
- 逻辑判断 :在 Lua 中,只有
false和nil被视为"假" 。所有其他值,包括数字0、空字符串"",在条件表达式中都被视为"真"。这一点与其他许多编程语言不同,需要特别注意。
3. number (数字)
number 类型用于表示数值。
- 不区分精度:Lua 不区分整数和浮点数,所有数字默认都是双精度浮点数。
- 多种表示 :支持十进制、十六进制(如
0xFF)和科学计数法(如2e3代表 2000)。
4. string (字符串)
string 类型用于表示文本。
- 不可变性:字符串一旦创建,其内容是不可改变的。
- 引号 :可以使用单引号
'...'或双引号"..."来定义,两者等价。 - 拼接 :使用两个点
..作为连接操作符,例如"Hello" .. " World"。 - 多行字符串 :使用
[[...]]可以方便地定义多行字符串,并且会保留其中的所有字符,不进行转义。
5. table (表)
table 是 Lua 中唯一的数据结构,功能极其强大和灵活,可以看作是"关联数组"。
- 多功能性:它可以被用作数组、字典(哈希表)、对象、模块等。
- 创建 :使用构造表达式
{}来创建一个空表。 - 索引 :
- 数组 :当用作数组时,索引默认从 1 开始,而不是 0。
- 字典 :可以使用任意非
nil值作为键(key)。
- 访问 :对于字符串键,
t["key"]和t.key两种写法等价,后者更简洁。
6. function (函数)
在 Lua 中,函数是一种"一等公民"(First-class Citizen),这意味着函数可以像普通变量一样被赋值、作为参数传递和作为返回值。
- 定义 :可以使用
function关键字定义命名函数,也可以使用匿名函数(function(...) ... end)并将其赋值给变量。 - 闭包:Lua 完美支持闭包,即函数可以捕获并持有其定义时所在作用域的变量。
单行注释
单行注释以两个连续的短横线 -- 开头,从 -- 开始直到行尾的所有内容都会被 Lua 解释器忽略。
使用场景:
-
对单行代码进行简短说明。
-
临时注释掉某一行代码。
-- 这是一个单行注释
print("Hello") -- 这也是一个单行注释,位于代码行尾
-- print("这行代码被注释掉了,不会执行")
📄 多行注释 (块注释)
多行注释,也称为块注释,用于注释掉大段的代码或编写详细的说明。它以 --[[ 开头,以 ]] 结尾。
基本语法:
--[[
这是一个多行注释。
可以包含很多行文本,
用于详细解释复杂的代码逻辑。
]]
print("Hello")
💡 进阶技巧:处理特殊情况
1. 注释内容中包含 ]]
如果你的注释内容中恰好包含了 ]] 字符串,会导致注释提前结束,引发语法错误。为了解决这个问题,Lua 允许你在注释的起始和结束标记中添加任意数量的等号 = 来配对。
示例:
--[=[
这是一个多行注释,
注意看下面这行,它包含了 ']]' 字符串,但不会导致注释结束。
local str = "这是一个 ]] 字符串"
--]=]
2. 快速开关多行注释
这是一个非常实用的技巧。如果你想快速地将一大段多行注释变为可执行代码,或者反过来,可以在 --[[ 前面再加一个短横线,变成 ---[[。
--[[ ... ]]是一个多行注释,内部代码不会执行。---[[ ... ]]中,---被视为一个单行注释,而[[ ... ]]则变成了一个多行字符串(在 Lua 中,多行字符串的语法是[[...]]),内部代码会被执行。
示例:
---[[
print("这行代码会被执行,因为外层是多行字符串,不是注释")
--]]
函数声明
这是最常见和直观的声明方式,使用 function 关键字。
-- 全局函数
function sayHello(name)
print("Hello, " .. name .. "!")
end
-- 局部函数 (推荐)
local function sayGoodbye(name)
print("Goodbye, " .. name .. "!")
end
sayHello("Alice") -- 输出: Hello, Alice!
sayGoodbye("Bob") -- 输出: Goodbye, Bob!
匿名函数赋值
函数可以不被命名,而是作为一个值(匿名函数)直接赋值给一个变量。这种方式在需要动态创建函数或作为回调时非常有用。
-- 将匿名函数赋值给一个局部变量
local myPrint = function(content)
print("[日志] " .. content)
end
-- 调用
myPrint("这是一个测试") -- 输出: [日志] 这是一个测试
函数核心特性
参数 (Arguments)
-
参数数量不匹配 :Lua 对参数数量非常宽容。如果调用时提供的参数少于定义,不足的参数会被自动赋值为
nil。如果提供的参数多于定义,多余的参数会被直接忽略。 -
可变参数 (Varargs) :使用三个点
...可以让函数接收任意数量的参数。这些参数可以在函数体内通过{...}构造成一个表(数组)来遍历和处理。-- 可变参数示例
local function addAll(...)
local args = {...} -- 将所有参数放入一个表中
local sum = 0
for i, v in ipairs(args) do
sum = sum + v
end
return sum
endprint(addAll(1, 2, 3)) -- 输出: 6
print(addAll(10, 20, 30, 40)) -- 输出: 100
返回值 (Return Values)
-
多重返回值 :这是 Lua 的一大特色。一个函数可以同时返回多个值,调用者可以使用多重赋值来接收它们。
- 如果接收变量少于返回值数量,多余的返回值会被丢弃。
- 如果接收变量多于返回值数量,多余的变量会被赋值为
nil。
-
默认返回 :如果函数执行完毕没有遇到
return语句,它会默认返回nil。-- 多重返回值示例
local function getUserInfo()
return "Alice", 25, "Engineer"
end-- 接收所有返回值
local name, age, job = getUserInfo()
print(name, age, job) -- 输出: Alice 25 Engineer-- 只接收第一个返回值
local onlyName = getUserInfo()
print(onlyName) -- 输出: Alice
作用域 (Scope)
和变量一样,函数也遵循作用域规则。
- 全局函数 :默认情况下,使用
function funcName()声明的函数是全局的,可以在任何地方被调用。 - 局部函数 :强烈建议 使用
local function funcName()来声明函数。这可以将函数限制在当前的代码块内,避免污染全局命名空间,是模块化编程的最佳实践。
在 Lua 中,变量声明的核心在于理解其动态类型 和作用域机制。与许多静态类型语言不同,Lua 的变量声明非常灵活,但也因此需要开发者格外注意,以避免潜在的错误。
核心特性:动态类型
Lua 是一种动态类型语言,这意味着:
-
变量本身没有类型 ,只有它所持有的值才有类型。
-
你无需在声明时指定变量的类型。
-
同一个变量可以在程序运行过程中被赋予不同类型的值。
local myVar = 10 -- myVar 现在是 number 类型
myVar = "Hello, Lua!" -- 现在 myVar 变成了 string 类型
myVar = true -- 现在 myVar 变成了 boolean 类型
📝 声明方式:全局与局部
Lua 中的变量根据其作用域分为两种:全局变量和局部变量。
局部变量 (Local Variables)
使用 local 关键字声明的变量是局部变量。它的作用域仅限于声明它的那个代码块 (例如函数内部、if 语句、for 循环或 do...end 块)。
local x = 10
local name = "Alice"
local t = {1, 2, 3}
全局变量 (Global Variables)
如果不使用 local 关键字,直接通过赋值创建的变量就是全局变量。全局变量在整个 Lua 环境中都是可见的,可以被任何地方访问和修改。
globalVar = "I am global" -- 这是一个全局变量
⚖️ 局部变量 vs. 全局变量
强烈推荐使用局部变量,原因如下:
- 避免命名冲突:局部变量的作用域是隔离的,可以防止不同模块或函数之间因使用相同变量名而互相干扰。
- 性能更优:Lua 访问局部变量的速度比访问全局变量更快。
- 防止内存泄漏 :局部变量在超出其作用域后,会很快被垃圾回收器(GC)回收。而全局变量会一直存在于全局环境表
_G中,可能导致内存无法及时释放。 - 提高代码可读性:将变量的作用域限制在必要的最小范围内,使代码逻辑更清晰,易于理解和维护。
示例:作用域对比
local globalCounter = 0 -- 这是一个局部变量,但在文件顶层,作用域是整个文件
function increase()
local localCounter = 0 -- 这是一个真正的局部变量,只在函数内有效
localCounter = localCounter + 1
globalCounter = globalCounter + 1
print("函数内 localCounter:", localCounter) -- 输出: 1
print("函数内 globalCounter:", globalCounter) -- 输出: 1
end
increase()
-- print(localCounter) -- 错误!localCounter 在此处不可见
print("函数外 globalCounter:", globalCounter) -- 输出: 1,值被保留了