模块级的计数器、限流器都面临一个问题:状态存全局容易被别的代码改坏。闭包把状态封在函数的作用域里,外部只能通过暴露的接口读写,计数器、工厂函数、限流器三种场景都能用闭包封装。
工厂函数返回一对读写闭包,计数变量只存在于闭包作用域,外部无法直改。actor是字符串,转对象后按玩家生成独立计数器。
local function newCounter(start)
local count = start or 0
local function add(step)
count = count + (step or 1)
return count
end
local function value()
return count
end
return add, value
end
local addKill, getKills = newCounter(0)
function killmon(actor)
addKill(1)
if getKills() >= 500 then
addKill(-500)
giveitem(actor, "屠魔证书", 1)
end
end
同一工厂为不同玩家生成独立限流器,状态互不串扰,接口只有允许与拒绝。actor是字符串,转对象后创建专属限流器。
local function newLimiter(limit, window)
local log = {}
return function(now)
for i = #log, 1, -1 do
if now - log[i] > window then
table.remove(log, i)
end
end
if #log >= limit then
return false
end
table.insert(log, now)
return true
end
end
local tradeAllow = newLimiter(5, 300)
计数器与限流器的边界值逐条断言;外部直改状态的路径验证不可达。上线后盘点闭包持有的状态量,长期不释放的闭包链会让内存缓慢增长,挂到玩家生命周期的闭包随下线清理。
闭包捕获的是变量本身不是值的拷贝,add与value共享同一个count,多处创建的计数器互不相干,想要全局唯一就只创建一次。限流器的log表在闭包里增长,窗口滑动清理靠调用驱动,长期无人调用的限流器表会残留旧记录。返回两个函数的写法在赋值顺序上要对齐,add与value拿反了业务会静默算错。闭包嵌套超过两层后可读性骤降,用表组织接口替代层层嵌套。
全站技术干货持续更新:996 引擎 / Lua 实战帖,语法、参数与示例一篇讲透。进入文章地图 · 查看全部 →
实战应用:用在哪里 装备回收商 NPC 每天按评分收购玩家的装备,裁决之杖、骨玉权杖按攻击、持久加权打分,榜上只要前五名。数…
实战应用:用在哪里 沙巴克攻城是全服行会战的最高舞台:攻方砸开城门、抢占皇宫,守方依托城墙与复活点反打。规则设计的关键是节奏…
实战应用:用在哪里 影分身玩法给法师职业补上生存短板:危急时刻召唤四个影分身分担仇恨,敌人需要在六格范围内分辨真身,猜错就浪…
实战应用:用在哪里 组队邀请、行会宣战这类关键信令丢了没有兜底,玩家只能反复手点,高峰期体验很差。重试机制给信令加确认回执:…
实战应用:用在哪里 新资料片上线首日预约量常是日常十倍,一口气全开会让数据库与登录网关同时过载。滚动开区把开区动作排成队列:…
实战应用:用在哪里 百人同屏的沙巴克外围战场,每个玩家每秒跑动会触发数次位置更新,全部即时下发时广播量随人数平方增长,网关先…