【语法算法】
元方法 __call 的触发就这一行:
setmetatable(t, { __call = function(self, ...) return ... end })
对带 __call 元方法的表做函数调用 t(...) 时,Lua 不报错而是调用 __call 的第一个参数传入表自身——让表变成函数的全部机制就这一行。今天拆开。
一、注册、调用、传参三段
__call 的三段。注册:元表的 __call 字段赋一个函数——这个函数的第一个参数永远是表自身——后续参数是调用时传入的实参。调用:t(args) 触发 __call(self, args)——表变成了"可调用的对象",调用时 Lua 自动把表自身作为第一个参数传入。传参:__call 的参数列表是 (self, ...)——self 就是表本身,后续参数按顺序对应调用时传入的实参。三段连起来:__call 玩的是"把数据和行为合为一体"——表既是数据容器又是可调用的函数,这就是函数式编程的核心思想。
graph TD
A["t(args)"] --> B{"t有__call?"}
B -->|是| C["调用__call(t, args)"]
C --> D["self = t"]
C --> E["后续参数 = args"]
B -->|否| F["报错: 试图调用一个表"]
二、可调用表的正确写法
local Calculator = setmetatable({}, {
__call = function(self, a, b, op)
if op == "+" then return a + b end
if op == "-" then return a - b end
if op == "*" then return a * b end
end
})
print(Calculator(3, 4, "+")) -- 7
print(Calculator(3, 4, "*")) -- 12
Calculator 是一个表——但它可以像函数一样被调用——调用时走 __call 元方法——self 参数自动传入表自身。
三、__call 与 __index 的联动
__call 和 __index 是元表中最常用的两个元方法——__index 管"读取不存在的键时怎么办",__call 管"把表当函数调用时怎么办"——两者组合可以实现"可调用的对象":表既是数据容器又可以通过调用触发行为。最后一条纪律:__call 的第一个参数永远是表自身——这个参数是 Lua 自动传入的,不需要也不应该在调用时手动传——如果 __call 函数的参数列表没有预留 self 位置,实参就会错位。
全站技术干货持续更新:996 引擎 / Lua 实战帖,语法、参数与示例一篇讲透。进入文章地图 · 查看全部 →
【游戏功能】 香烧着的时候,人心最定。焚香把这句老话做成了机制:点一炷八秒的香,香烧着的三刀一叩首——每叩一回,血回六点。香…
【游戏功能】 下一封战书是什么概念?是你和它同时签下"六秒内往死里打"的字据:你加三,它加四——它的刀更疼,你的刀也不再客气…
【游戏功能】 日志里躺着一条没人在意的细节:某只头目的治疗明细里,回血来源写着一颗珠子的名字——两颗珠子轮流替它回血,每两秒…
【游戏功能】 oil = oil - 1 —— 灯芯上两秒烧掉的一滴油,就是挑灯的全部家底:灯亮着,刀足十;油见底,刀软成五…
【游戏功能】 守塔组出过一单静悄悄的失误:同一批怪,同样的守塔人,有的晚上一血没掉,有的被摸了三回——查录像才发现,守得住的…
【游戏功能】 为什么有些玩家越打越软?前二十刀刀刀十点,二十刀之后刀刀四点——装备没变,变的是气。匀气把这件事做成了明账:五…