我很确定在Lua中,您可以使用给定的metatable的__index,__ newindex和__call来粗略地复制 Ruby的method_missing.我有点: function method_missing(selfs, func) local meta = getmetatable(selfs) local f if meta then f = meta.
function method_missing(selfs, func) local meta = getmetatable(selfs) local f if meta then f = meta.__index else meta = {} f = rawget end meta.__index = function(self, name) local v = f(self, name) if v then return v end local metahack = { __call = function(self, ...) return func(selfs, name, ...) end } return setmetatable({}, metahack) end setmetatable(selfs, meta) end _G:method_missing(function(self, name, ...) if name=="test_print" then print("Oh my lord, it's method missing!", ...) end end) test_print("I like me some method_missing abuse!") print(this_should_be_nil)
我的问题是:虽然语法类似,我当然可以使用它来复制功能,但它引入了一个突破性的错误.你在应用method_missing的表的上下文中使用的每个变量永远都不是nil,因为我必须返回一个可以被调用的对象,以便将潜在调用的降压从索引函数传递给实际的调用.
ie在定义了如上所述的全局method_missing之后,尝试调用未定义的方法’test_print’按预期运行,但是当索引时test_print的值是非零的,并且未响应的其他方法/变量,如this_should_be_nil是非零.
那么有可能避免这个陷阱吗?或者,如果不修改语言源本身,语法是否可以支持这种修改?我想象在Ruby中,索引和调用是如何类似的,而在Lua中它们是截然不同的.
您可以通过使nil值可调用来避免此问题.不幸的是,这只能从主机代码(即C程序)完成,而不能从Lua脚本完成.
Pascal代码:
function set_metatable_for_any_value_function(L: Plua_State): Integer; cdecl; begin // set_metatable_for_any_value(any_value, mt) lua_setmetatable(L, -2); Result := 0; end; procedure Test_Proc; var L: Plua_State; const Script = 'set_metatable_for_any_value(nil, ' + ' { ' + ' __call = function() ' + ' print "This method is under construction" ' + ' end ' + ' } ' + ') ' + 'print(nonexisting_method == nil) ' + 'nonexisting_method() '; begin L := luaL_newstate; luaL_openlibs(L); lua_pushcfunction(L, lua_CFunction(@set_metatable_for_any_value_function)); lua_setglobal(L, 'set_metatable_for_any_value'); luaL_dostring(L, Script); lua_close(L); end;
输出:
true This method is under construction