Lua语法详解:从变量声明到循环遍历的避坑指南

在上一篇文章中,我们认识了 Lua 这种轻量级脚本语言,并成功运行了 Hello World。但在实际的多级缓存开发(如 Nginx + OpenResty)中,仅仅会打印字符串是远远不够的。

Lua 的语法设计非常独特,它既像 Python 一样简洁,又像 Java 一样严谨,但又有许多"反直觉"的特性(比如数组下标从 1 开始)。今天,我们就来深入 Lua 的核心------变量与循环,帮你避开那些新手最容易踩的坑。

一、Lua 的数据类型:少即是多

与 Java 复杂的类型系统不同,Lua 只有寥寥几种基本类型,但却极其灵活。

  • nil(空值)
    • 表示无效值。在条件判断中,nil 和 false 都会被当作"假",而其他任何值(包括 0 和空字符串 "")都被当作"真"。
    • 注意:这与 Java 的 null 不同,Java 的 null 不能直接参与逻辑运算。
  • boolean(布尔)
    • 只有 true 和 false。
  • number(数字)
    • Lua 不区分 int、float 或 double,所有数字默认都是双精度浮点数。
    • 示例:10.4 * 3 的结果依然是 number 类型。
  • string(字符串)
    • 支持单引号 ' 和双引号 ",两者等价。
    • 拼接:使用两个点 .. 操作符,例如 "Hello" .. "World"。
  • function(函数)
    • 函数在 Lua 中是"一等公民",可以像变量一样被赋值和传递。
  • table(表)
    • 这是 Lua 最强大的数据结构!它既是数组,也是 Map(哈希表)。
    • 创建:使用 {} 即可,例如 local arr = {}。

小技巧:如何判断类型?

使用 type() 函数,它会返回一个字符串表示类型:

复制代码
print(type("Hello")) -- 输出 "string"
print(type(10.4*3))  -- 输出 "number"
print(type(print))   -- 输出 "function"
二、变量声明:local 是必须的

在 Java 中,我们习惯写 int a = 10;。而在 Lua 中,声明变量非常简单,但有一个关键规则:一定要加 local

1. 声明语法

不需要指定类型,直接赋值即可:

复制代码
local str = 'hello'            -- 字符串
local num = 21                 -- 数字
local flag = true              -- 布尔
local arr = {'java', 'lua'}    -- 数组形式的 table
local map = {name='Jack', age=21} -- Map 形式的 table

2. 为什么要用 local?

  • 局部变量:使用 local 声明的变量,作用域仅限于当前代码块。
  • 全局变量:如果不加 local,变量默认是全局的。
  • 最佳实践 :在 Nginx 脚本中,为了避免污染全局环境并提升访问速度,请务必始终使用 local 声明变量

3. 访问 Table

Lua 的 table 非常灵活,访问方式也多种多样:

  • 数组访问
    • 注意!Lua 的数组下标从 1 开始,而不是 0!
    • 示例:print(arr[1]) 获取第一个元素。
  • Map 访问
    • 方式一(中括号):print(map['name']),类似 Java 的 map.get("name")。
    • 方式二(点号):print(map.name),类似 Java 的对象属性访问。
    • 两者完全等价,点号写法更简洁。
三、循环遍历:ipairs 与 pairs 的爱恨情仇

在 Java 中,我们遍历 List 用 for-each,遍历 Map 用 entrySet。在 Lua 中,我们需要根据 table 的形态选择不同的迭代器。

1. 遍历数组:使用 ipairs

当你把 table 当作数组(连续的数字索引)使用时,使用 ipairs。

复制代码
local arr = {'java', 'python', 'lua'}
for index, value in ipairs(arr) do
    print(index, value)
end
-- 输出: 1 java, 2 python, 3 lua

2. 遍历 Map:使用 pairs

当你把 table 当作字典(键值对)使用时,必须使用 pairs。

复制代码
local map = {name='Jack', age=21}
for key, value in pairs(map) do
    print(key, value)
end
-- 输出: name Jack, age 21 (顺序可能不固定)

避坑指南:

  • 遍历纯数组时,推荐用 ipairs,因为它效率更高且按顺序遍历。
  • 遍历包含非数字 Key 的 table 时,必须用 pairs。
总结与展望

Lua 的语法虽然简单,但 table 的灵活性和下标从 1 开始的设定往往是 Java 开发者最容易出错的地方。

掌握了变量和循环,我们就拥有了编写复杂逻辑的能力。接下来,我们就可以利用这些知识,去探索 Lua 的函数定义和模块管理,真正开始编写 Nginx 业务脚本了。


知识点核心总结
知识点 核心内容 考试重点/易混淆点 难度系数
Lua数据类型 nil(可表示false)、boolean、number(统一数值类型)、string(单/双引号)、function(可传递)、table(数组+map混合结构) nil与false的等价性、table的两种形态转换 ⭐⭐
变量声明 local声明局部变量(不加local为全局变量),无需指定类型 字符串拼接使用..运算符
table操作 数组角标从1开始、map支持table.key和table["key"]两种访问方式 角标从1开始与多数语言差异 ⭐⭐
循环结构 for index,value in ipairs(arr)遍历数组 for key,value in pairs(map)遍历table ipairs/pairs函数选择 ⭐⭐
类型检测 type()函数返回类型字符串(nil/boolean/number/string/function/table) 检测函数类型返回"function"
语法特性 函数作为一等公民可赋值传递、table的灵活数据结构 设计与JAVA的类型系统差异对比 ⭐⭐⭐
相关推荐
上海合宙LuatOS2 小时前
LuatOS扩展库API——【exmodbus】MODBUS协议
物联网·lua·luatos
一个有温度的技术博主3 小时前
深入多级缓存:JVM进程缓存实战与数据库表拆分策略
jvm·数据库·缓存
一个有温度的技术博主3 小时前
Lua语法进阶:函数封装与条件控制的艺术
redis·分布式·缓存·lua
一个有温度的技术博主3 小时前
突破性能极限:深入解析多级缓存架构设计与实践
redis·缓存
手握风云-3 小时前
Redis:不只是缓存那么简单(三)
缓存
白露与泡影3 小时前
Spring Boot 缓存架构:一行配置切换 Caffeine 与 Redis,透明支持多租户隔离
spring boot·缓存·架构
roman_日积跬步-终至千里3 小时前
【系统架构师-案例题-分布式数据缓存架构】22年下(3)分布式仓储货物管理系统
分布式·缓存·系统架构
北有树4 小时前
Redis专题面试题总结
数据库·redis·缓存
rannn_1114 小时前
【Redis|实战篇7】黑马点评|附近商铺、用户签到、UV签到
java·数据库·redis·后端·uv