Lua语法入门-条件控制、函数

一、前言:为什么条件和函数是 Lua 脚本的核心?

在 Redis 中,你经常需要实现这样的逻辑:

  • "如果库存足够,就扣减;否则返回失败"
  • "对多个 key 执行相同操作,避免重复代码"

条件控制(if)决定逻辑分支,函数(function)实现代码复用 ------它们是构建健壮、可维护 Lua 脚本的两大支柱!

本文将带你深入掌握 Lua 的 if 语句、布尔逻辑、函数定义与调用,并结合 Redis 实战演示。


二、条件控制:if 语句全解析

Lua 的条件判断非常简洁,但有两个关键细节必须注意!

2.1 基本语法

Lua 复制代码
if condition1 then
    -- 执行块1
elseif condition2 then
    -- 执行块2
else
    -- 执行块3
end

2.2 关键规则 1:只有 nil 和 false 是"假"

Lua 复制代码
-- 以下值在 if 中都为"真"!
if 0 then print("0 是真") end          --> 输出
if "" then print('空字符串是真') end   --> 输出
if {} then print("空表是真") end       --> 输出

-- 只有这两个是"假"
if nil then else print("nil 是假") end
if false then else print("false 是假") end

⚠️ 常见坑 :不要写 if count == nil or count == 0,直接 if not count 即可(但注意 0 是真!)

2.3 关键规则 2:关系运算符

运算符 含义
== 相等
~= 不等(不是 !=)
<, >, <=, >= 比较大小
Lua 复制代码
local a = 10
local b = "10"

print(a == b)  --> false(类型不同)
print(a == tonumber(b)) --> true

建议 :比较前统一类型(如用 tonumber() 转数字)


三、实战:Redis 脚本中的条件判断

场景:安全扣减库存(防止超卖)

Lua 复制代码
-- safe_decr_stock.lua
local stock_key = KEYS[1]
local decr_amount = tonumber(ARGV[1])

-- 获取当前库存(字符串转数字)
local current = redis.call('GET', stock_key)
if not current then
    -- 库存未初始化
    return 0
end

local stock = tonumber(current)
if stock >= decr_amount then
    redis.call('DECRBY', stock_key, decr_amount)
    return 1  -- 成功
else
    return 0  -- 库存不足
end

优势 :整个判断+修改过程原子执行,无并发问题!


四、函数(Function):代码复用的关键

4.1 定义函数

Lua 复制代码
-- 方式1:标准定义
function add(a, b)
    return a + b
end

-- 方式2:变量赋值(等价)
add = function(a, b)
    return a + b
end

4.2 调用函数

Lua 复制代码
local result = add(3, 5)
print(result)  --> 8

4.3 函数特性

  • 多返回值

    Lua 复制代码
    function get_name_age()
        return "Alice", 25
    end
    local name, age = get_name_age()
  • 可变参数

    Lua 复制代码
    function sum(...)
        local args = {...}
        local total = 0
        for i = 1, #args do
            total = total + args[i]
        end
        return total
    end
    print(sum(1, 2, 3))  --> 6

💡 提示 :Redis 脚本中不推荐使用可变参数,因 ARGV 已是 table。


五、Redis 脚本中的函数实践

场景:封装"获取并转数字"逻辑

Lua 复制代码
-- utils.lua (嵌入到主脚本中)
local function get_number(key)
    local val = redis.call('GET', key)
    if not val then return 0 end
    return tonumber(val)
end

-- 主逻辑
local stock = get_number(KEYS[1])
local quota = get_number(KEYS[2])

if stock > 0 and quota > 0 then
    redis.call('DECR', KEYS[1])
    redis.call('DECR', KEYS[2])
    return "OK"
else
    return "INSUFFICIENT"
end

好处

  • 避免重复代码
  • 逻辑更清晰
  • 易于测试和维护

六、高级技巧:函数作为参数(高阶函数)

Lua 支持函数式编程风格:

Lua 复制代码
-- 定义一个通用遍历处理器
local function process_keys(key_list, handler)
    for i = 1, #key_list do
        handler(key_list[i])
    end
end

-- 使用
process_keys(KEYS, function(key)
    redis.call('EXPIRE', key, 3600)
end)

🔧 适用场景:批量设置过期时间、统一格式化等。


七、避坑指南:Redis 脚本中的函数限制

❌ 不能定义全局函数(除非必要)

Lua 复制代码
-- 危险!污染全局环境
function my_func() ... end

-- 安全:用 local
local function my_func() ... end

❌ 不能递归过深(Redis 有栈深度限制)

  • 避免深度递归,改用循环

❌ 函数内不能有随机行为

Lua 复制代码
-- 错误:math.random() 在 Redis 中禁止(除非固定种子)
local function random_val()
    return math.random(1, 10)  -- 可能导致主从不一致!
end

替代方案:随机数由客户端生成,通过 ARGV 传入。


八、小结:核心要点速记

主题 关键规则
if 判断 只有 nilfalse 为假;0、""、{} 都是真
不等于 ~=,不是 !=
函数定义 local function name(...) ... end
Redis 安全 函数必须是纯函数(无副作用、无随机)
代码复用 将通用逻辑(如类型转换)封装成 local 函数

九、结语

感谢您的阅读!如果你有任何疑问或想要分享的经验,请在评论区留言交流!

相关推荐
W.A委员会17 小时前
JS原型链详解
开发语言·javascript·原型模式
止语Lab17 小时前
Go并发编程实战:Channel 还是 Mutex?一个场景驱动的选择框架
开发语言·后端·golang
她说彩礼65万18 小时前
C# 实现简单的日志打印
开发语言·javascript·c#
绿浪198418 小时前
c# 中结构体 的定义字符串字段(性能优化)
开发语言·c#
房开民18 小时前
可变参数模板
java·开发语言·算法
t***54419 小时前
如何在现代C++中更有效地应用这些模式
java·开发语言·c++
Victoria.a20 小时前
python基础语法
开发语言·python
xiaoyaohou1120 小时前
023、数据增强改进(二):自适应数据增强与AutoAugment策略
开发语言·python
鬼圣20 小时前
Python 上下文管理器
开发语言·python
星空椰21 小时前
JavaScript 基础进阶:分支、循环与数组实战总结
开发语言·javascript·ecmascript