Lua是一种动态类型语言,变量没有固定的类型,但值有明确的类型。理解这8种数据类型的特性和内部实现原理,对于编写高效、健壮的Lua代码至关重要。
| 类型 | 说明 | 内部实现 | 内存管理 | 示例 |
|---|---|---|---|---|
| nil | 空值,表示无效值 | 特殊标记值 | 不占用堆内存 | nil |
| boolean | 布尔值 | 1字节存储 | 不占用堆内存 | true, false |
| number | 数字(整数和浮点数) | 64位存储(整数或浮点) | 不占用堆内存 | 123, 3.14 |
| string | 字符串 | 引用计数,内部化 | 垃圾回收管理 | "hello", 'world' |
| table | 表(数组、字典) | 哈希表+数组混合 | 垃圾回收管理 | {1, 2, 3} |
| function | 函数 | 闭包,包含代码和环境 | 垃圾回收管理 | function() end |
| userdata | C数据结构 | 外部内存块 | 垃圾回收或手动管理 | - |
| thread | 协程 | 独立的执行栈 | 垃圾回收管理 | coroutine |
type()函数统一处理Lua使用一个统一的类型系统来表示所有值:
-- Lua内部使用一个联合体(union)来表示值
typedef struct {
int tt; /* 类型标签 */
Value value; /* 实际值 */
} TValue;
/* Value是一个联合体,根据类型存储不同的数据 */
typedef union {
lua_Number n; /* 数字 */
GCObject *gc; /* 垃圾回收对象(字符串、表等) */
void *p; /* 轻量级用户数据 */
int b; /* 布尔值 */
} Value;
这种设计使得Lua能够:
nil是Lua中最基础的类型,表示"没有值"或"未定义"。理解nil的语义和内部实现对于编写健壮的Lua代码非常重要。
-- nil表示空值
local x -- 未初始化的变量默认为nil
print(x) -- 输出: nil
print(type(x)) -- 输出: nil
-- 删除变量
y = 10
y = nil -- 删除y,释放引用
print(y) -- 输出: nil
-- 检查变量是否存在
if someUndefinedVar == nil then
print("变量不存在")
end
在Lua虚拟机中,nil的实现非常高效:
-- Lua内部,nil是一个特殊的标记值
#define LUA_TNIL 0 /* nil类型标签 */
/* 在TValue结构中,nil类型不需要存储实际值 */
TValue nil_value = {LUA_TNIL, {0}};
/* 检查是否为nil的宏 */
#define ttisnil(o) (ttype(o) == LUA_TNIL)
-- 1. 可选参数处理
function greet(name, greeting)
greeting = greeting or "Hello" -- 如果greeting为nil,使用默认值
return greeting .. ", " .. name
end
print(greet("Alice")) -- 输出: Hello, Alice
print(greet("Bob", "Hi")) -- 输出: Hi, Bob
-- 2. 表元素的删除
local person = {name = "张三", age = 25}
print(person.name) -- 输出: 张三
person.name = nil -- 删除name字段
print(person.name) -- 输出: nil
-- 3. 函数返回值表示失败
function findUser(id)
-- 模拟查找用户
if id == 1 then
return {name = "Alice", age = 30}
else
return nil -- 用户不存在
end
end
local user = findUser(2)
if user == nil then
print("用户不存在")
end
-- 4. 条件判断中的nil
local value = nil
if not value then
print("值为nil或false") -- 会执行
end
or操作符为nil值提供默认值Lua的布尔类型只有两个值:true和false。但Lua的真值系统更为复杂,理解这一点对于编写正确的条件判断至关重要。
-- 布尔值定义
local a = true
local b = false
print(type(a)) -- 输出: boolean
print(type(b)) -- 输出: boolean
-- 布尔运算
print("true and false:", true and false) -- 输出: false
print("true or false:", true or false) -- 输出: true
print("not true:", not true) -- 输出: false
-- 比较运算返回布尔值
print("10 > 5:", 10 > 5) -- 输出: true
print("10 == 5:", 10 == 5) -- 输出: false
在条件判断中,Lua遵循以下规则:
false和nil-- 测试各种值的真值性
local values = {
nil, false, true,
0, 1, -1, 3.14,
"", "hello",
{}, {1,2,3},
function() end
}
for i, value in ipairs(values) do
if value then
print("值", i, "是真值")
else
print("值", i, "是假值")
end
end
Lua内部使用整数来表示布尔值:
-- Lua内部布尔值定义
#define LUA_TBOOLEAN 1 /* 布尔类型标签 */
/* 布尔值存储 */
#define bvalue(o) check_exp(ttisboolean(o), (o)->value.b)
/* true和false的内部表示 */
#define LUA_VTRUE makevariant(LUA_TBOOLEAN, 1)
#define LUA_VFALSE makevariant(LUA_TBOOLEAN, 0)
/* 检查布尔值的宏 */
#define ttisboolean(o) (ttype(o) == LUA_TBOOLEAN)
Lua的and和or操作符使用短路求值,这是编写简洁代码的重要技巧:
-- and操作符:如果第一个操作数为假,直接返回第一个操作数
print("nil and 10:", nil and 10) -- 输出: nil
print("false and 10:", false and 10) -- 输出: false
print("true and 10:", true and 10) -- 输出: 10
-- or操作符:如果第一个操作数为真,直接返回第一个操作数
print("nil or 10:", nil or 10) -- 输出: 10
print("false or 10:", false or 10) -- 输出: 10
print("true or 10:", true or 10) -- 输出: true
-- 实用技巧:提供默认值
local name = userInput or "匿名用户"
local port = config.port or 8080
-- 安全访问嵌套属性
local userName = user and user.profile and user.profile.name or "未知"
-- 1. 条件判断
local age = 25
local isAdult = age >= 18
if isAdult then
print("成年人")
else
print("未成年人")
end
-- 2. 标志变量
local isRunning = true
local hasError = false
-- 3. 函数返回值表示状态
function validateEmail(email)
if string.find(email, "@") then
return true, "邮箱格式正确"
else
return false, "邮箱格式错误"
end
end
local valid, message = validateEmail("test@example.com")
if valid then
print("验证通过:", message)
else
print("验证失败:", message)
end
-- 4. 配置开关
local config = {
debug = true,
logging = false,
cacheEnabled = true
}
if config.debug then
print("调试信息: 程序正在运行")
end
isValid、hasPermission-- 整数
local age = 25
local count = -10
-- 浮点数
local pi = 3.14159
local price = 99.99
-- 科学计数法
local big = 1.5e10 -- 15000000000
local small = 1.5e-3 -- 0.0015
-- 十六进制
local hex = 0xFF -- 255
print(type(age)) -- 输出: number
-- 单引号和双引号都可以
local str1 = "Hello"
local str2 = 'World'
-- 多行字符串
local str3 = [[
这是一个
多行字符串
]]
-- 字符串拼接
local name = "Lua"
local greeting = "Hello, " .. name .. "!"
print(greeting) -- 输出: Hello, Lua!
-- 字符串长度
print(#greeting) -- 输出字符串长度
-- 转义字符
local str4 = "第一行\n第二行\t制表符"
-- 全局变量(不推荐)
globalVar = "我是全局变量"
-- 局部变量(推荐)
local localVar = "我是局部变量"
-- 多变量赋值
local x, y, z = 1, 2, 3
print(x, y, z) -- 输出: 1 2 3
-- 交换变量
local a, b = 10, 20
a, b = b, a -- 交换
print(a, b) -- 输出: 20 10
-- 变量数量不匹配
local m, n = 1 -- n为nil
local p, q = 1, 2, 3 -- 3被忽略
-- type()函数检查类型
print(type(nil)) -- nil
print(type(true)) -- boolean
print(type(123)) -- number
print(type("hello")) -- string
-- 类型转换
local num = 100
local str = tostring(num) -- 数字转字符串
print(type(str)) -- string
local str2 = "456"
local num2 = tonumber(str2) -- 字符串转数字
print(type(num2)) -- number
-- 字符串自动转换
print("10" + 20) -- 输出: 30
print("3.14" * 2) -- 输出: 6.28
.. 操作符