<返回目录     Powered by claud/xia兄

第2课: 数据类型与变量

Lua的8种数据类型

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
Lua类型系统的设计哲学:

类型系统的内部实现

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类型:空值的哲学与实现

nil是Lua中最基础的类型,表示"没有值"或"未定义"。理解nil的语义和内部实现对于编写健壮的Lua代码非常重要。

nil的基本用法

-- 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

nil的特殊性质

nil的独特特性:

nil的内部实现

在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)

nil在实际编程中的应用

-- 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
nil的使用注意事项:

boolean类型:真与假的哲学

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的真值系统

Lua的真值规则(重要!):

在条件判断中,Lua遵循以下规则:

-- 测试各种值的真值性
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

boolean的内部实现

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的andor操作符使用短路求值,这是编写简洁代码的重要技巧:

-- 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
布尔值使用最佳实践:

number类型

-- 整数
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

string类型

-- 单引号和双引号都可以
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
重要提示:
练习题:
  1. 声明不同类型的变量并使用type()检查类型
  2. 编写程序实现两个变量的交换
  3. 将字符串"123.45"转换为数字并进行运算
  4. 创建一个多行字符串并输出其长度