Lua中的元表声明不支持语法糖

我正在尝试添加类似Python中的字符串索引。这行得通:

getmetatable('').__index = function(str, i) return string.sub(str, i, i) end

str1 = 'hello'
print(str1[1])

但这行不通:

getmetatable('').__index = function(str, i) return str:sub(i, i) end

会产生以下错误:

lua: test.lua:1: C stack overflow
stack traceback:
    test.lua:1: in function '__index'
    test.lua:1: in function '__index'
    ...
    test.lua:1: in function '__index'
    test.lua:4: in main chunk
    [C]: in ?

是否存在某种循环?为什么会发生这种情况?

点赞
用户805875
用户805875

str:method 快捷方式使用 __index。通过重新定义 __index,你打破了这个规则。

从 5.2 或 5.3 开始,Lua 定义了一个字符串的元表,大致如下:

debug.setmetatable( "", { __index = string } )

它允许编写 ("foo"):sub( i, j )


现在你会说

getmetatable('').__index = function(str, i) return str:sub(i, i) end

因此,如果你输入 ("foo")[2],那就调用 __index( "foo", 2 ),然后在其中查找 ("foo")["sub"](在 str:sub(i, i) 中)。这将调用 __index( "foo", "sub" ),然后在其中查找 ("foo")["sub"](在 str:sub(i, i) 中)。这将调用 __index( "foo", "sub" ),然后...

...由于你一直查找 ("foo")["sub"],导致堆栈溢出。


以你的方式重新定义 __index,意味着你不能再使用这种快捷方式,这意味着在你的代码、你使用的库代码中,你必须用 string.method 代替 str:method 每次使用—— 或者你保持兼容性。

仅针对数字才有意义的字符索引,因此,你可以通过如下方式同时实现:

getmetatable( "" ).__index = function( str, k )
    if type( k ) ~= "number" then  return string[k]  end -- lookup in string.*
    return str:sub( k, k )
end

这只会为数字索引调用 string.sub。方法名称是字符串,因此它们仍然会在 string 中查找。

2017-08-31 15:51:55