【语法算法】
rawlen 的本质就这一行:
local n = rawlen(t)
rawlen 绕过 __len 元方法直接返回表的原始长度——rawlen 的全部语义就这一行。可这一行的存在意义在于:当表设了 __len 元方法时,#t 走元方法而 rawlen 走原始操作——两者可能返回不同的值。今天拆开。
一、原始、元方法、分野三段
rawlen 的三段。原始:rawlen 直接返回表的数组部分长度——不查元表不调 __len——原始操作就是"无中间人"。元方法:#t 如果表的元表有 __len——走 __len 元方法返回自定义长度——原始长度被覆盖。分野:rawlen 和 #t 的分野在"设了 __len 的表"——没设元方法的表两者返回相同值——设了 __len 的表两者可能不同。三段连起来:rawlen 玩的是"绕过抽象层直接看底层"——调试和性能分析时 rawlen 比 # 更诚实。
graph TD
A["rawlen(t)"] --> B["直接返回数组长度"]
C["#t"] --> D{"t有__len?"}
D -->|是| E["调用__len(t)"]
D -->|否| F["返回数组长度"]
E --> G["返回自定义长度"]
二、rawlen 的正确写法
local container = setmetatable({ data = {1, 2, 3} }, {
__len = function(t) return #t.data * 2 end -- 故意翻倍
})
print(#container) -- 6: 走__len返回翻倍值
print(rawlen(container)) -- 0: container表自身没有数组部分
print(rawlen(container.data)) -- 3: data表的真实长度
rawlen 对 container 返回 0——因为 container 表的数组部分为空——__len 元方法返回的是 data 表的长度乘 2——rawlen 看到的是原始结构不是抽象层。
三、rawlen 的定位与调试的武器
rawlen 的定位是调试武器而非业务工具:业务代码永远用 # 操作符——rawlen 只在调试和性能分析时使用——用 rawlen 替代 # 是语义错误,两者返回值可能不同。和 rawget/rawset 的家族关系也值得记:rawget 绕过 __index 直读、rawset 绕过 __newindex 直写、rawlen 绕过 __len 直量——raw 家族的三个函数共同组成"绕过元表的原始操作集"——调试时用 raw 家族逐层排查,就能定位问题出在哪一层元方法。最后一条纪律:rawlen 只对表生效——对字符串 rawlen 会报错——字符串的长度用 #str 或 string.len(str)——不要混用 rawlen 和 string.len。
全站技术干货持续更新:996 引擎 / Lua 实战帖,语法、参数与示例一篇讲透。进入文章地图 · 查看全部 →
【游戏功能】 上一版藏了条只在长战斗里露头的隐蔽报错:吞劲的计数器跨场不清零——第一场怪喂满了五拳把它噎住,第二场新怪刚出手…
【游戏功能】 再抛一个坑:血条的长短是天生的吗?一只怪的命根子一千点,打完就满,下回见面还是一千点——命根是它自己的,跟你的…
【游戏功能】 var over=d-before ——先拆这一行。刀额减去落刀前的血,多出来的那一截就是杀过头的余劲。顺劈纹…
【游戏功能】 上一轮的线上事故出得难看:有玩家押了二十滴血没在限期内斩掉怪,注被纹收走了,直接在频道里喊"强买强卖"。复盘下…
【游戏功能】 上一版留了个查了半天的隐蔽报错:战斗统计里玩家的出招间隔写着一秒四,实际手感却是一秒整——两套计时账对不上,运…
【游戏功能】 先抛一个坑:你砍出去的最强一刀,去哪了?暴击三千的天胡刀,数字蹦完就散,下一刀又是从零起算——最强的那一击在战…