一般来说,语法:
for k, v in pairs(t) do
....
end
Run Code Online (Sandbox Code Playgroud)
相当于:
for k, v in next, t do
....
end
Run Code Online (Sandbox Code Playgroud)
但如果t有一个__pairsmetamethod怎么办?标准next()功能会检查这个吗?如果没有,那么在迭代表时总是使用pairs并且从不next()直接调用是不是更好?
我无法理解为什么__index这些示例之间的元方法行为存在差异:
A = { __index = A }
function A:speak()
print("I'm an A")
end
An_A = setmetatable({},A)
An_A:speak()
Run Code Online (Sandbox Code Playgroud)
会引发以下错误: lua: l.lua:8: attempt to call method 'speak' (a nil value)
同时
B = { __index = function(t,key) return B[key] end }
function B:speak()
print("I'm an B")
end
An_B = setmetatable({},B)
An_B:speak()
Run Code Online (Sandbox Code Playgroud)
将按预期执行,输出I'm an B.
在试图理解为什么会这样的情况下,我阅读了PiL的这一部分.它指出:
使用__index元方法进行继承是如此常见,以至于Lua提供了一种快捷方式.尽管有名称,但__index元方法不需要是一个函数:它可以是一个表,而不是.当它是一个函数时,Lua用表和缺席键作为参数来调用它.当它是一个表时,Lua重做该表中的访问权限.
我对此的理解是,在涉及"A"的代码段中,__index = A导致访问在表中完成A(根据上面引用的加速分段).如果是这种情况,我不明白为什么"speak"找不到与密钥相关的功能.为了尝试修复此问题,我决定在B代码段中实现函数方法,该方法返回与keyin 关联的值B,并且它有效.当然__index = …
有没有人知道lua 5.2的实际实现.metamethod __pairs?换句话说,我如何__pairs在metatable中实现metame方法,以便它与...完全相同pairs()?
我需要覆盖__pairs并希望跳过我在表中添加的一些虚拟变量.
背景
我和Watusimoto在Bitfighter游戏上合作.我们使用LuaWrapper的变体将我们的c ++对象与游戏中的Lua对象连接起来.我们还使用称为lua-vec的Lua变体来加速向量操作.
我们一直在努力解决一段时间没有找到错误的bug.将发生随机崩溃,表明腐败的元数据.有关Watusimoto的帖子,请参阅此处.我不确定这是因为一个腐败的metatable,并且看到了一些我想在这里问的非常奇怪的行为.
问题表现形式
作为一个例子,我们创建一个对象并将其添加到这样的级别:
t = TextItem.new()
t:setText("hello")
levelgen:addItem(t)
Run Code Online (Sandbox Code Playgroud)
但是,游戏有时会(并非总是)崩溃.出错:
attempt to call missing or unknown method 'addItem' (a nil value)
Run Code Online (Sandbox Code Playgroud)
使用上面提到的Watusimoto帖子中给出的建议,我已将最后一行更改为以下内容:
local ok, res = pcall(function() levelgen:addItem(t) end)
if not ok then
local s = "Invalid levelgen value: "..tostring(levelgen).." "..type(levelgen).."\n"
for k, v in pairs(getmetatable(levelgen)) do
s = s.."meta "..tostring(k).." "..tostring(v).."\n"
end
error(res..s)
end
Run Code Online (Sandbox Code Playgroud)
这打印出metatable,levelgen如果错误的话从它调用一个方法.
然而,这很疯狂,当它失败并打印出metatable时,metatable 正是应该如何(使用正确的addItem调用和所有内容).如果我levelgen在脚本加载时打印metatable ,并且在上面使用它时失败pcall,它们是相同的,每个调用和指向userdata的指针是相同的,应该是它.
好像metatable levelgen …
我之前问过为什么我的方法不是由Lua找到我的方法,并且被告知通过设置__index我的metatable,它会解决问题,所以我假设一个方法被调用时是通过metatable中的索引进行搜索,但我已经遇到了一个问题,现在我需要使用索引括号[和]我的元表,因此__index被分配到从它里面的一张桌子返回索引,我该如何解决您在使用这两种方法的功能需求和使用索引括号
我写了一个指示问题的最小例子:
TestMetatable = {DataTable = {}}
TestMetatable.__index = TestMetatable
function TestMetatable.new()
local Tmp = {}
setmetatable(Tmp,TestMetatable)
Tmp.DataTable = {1}
return Tmp
end
function TestMetatable:TestMethod()
print("Ran Successfully")
end
function TestMetatable.__index(self,index)
return self.DataTable[index]
end
local Test = TestMetatable.new()
-- both functionalities are needed
print(Test[1])
Test:TestMethod()
Run Code Online (Sandbox Code Playgroud) 假设我们有一个传递给函数的表,它现在位于堆栈顶部,如下所示:
// -1 = table
Run Code Online (Sandbox Code Playgroud)
是否可以从堆栈中的表中获取元表?我可以简单地使用已知名称标识符来获取它,如下所示:
luaL_getmetatable(L, "Foo");
Run Code Online (Sandbox Code Playgroud)
但我想重新使用该函数并从堆栈中的表中获取元表.
可能有一种简单的方法可以做到这一点,但我似乎找不到这个功能.
在以下示例中,将userdata创建一个类型的值,MyType并使用__tostring调用的元函数创建一个表LI_MyType__tostring.该代码创建了一个基于闭包的lua OOP.我对提供的示例的抱怨似乎只有一种方法可以userdata通过upvalues与方法调用相关联.除非我想跨实例共享相同的元表,否则这本身并不成问题.
在一个理想的世界 - 以及我希望用这个问题发掘的东西 - 有没有办法将upvalue与值(例如userdata)相关联,而不通过upvalue将它与函数调用相关联?我希望有一个技巧可以让我继续使用基于闭包的lua OOP 并在实例之间共享相同的元数据.我不乐观,但我想我会问是否有人有建议或不明显的伎俩.
using FuncArray = std::vector<const ::luaL_Reg>;
static const FuncArray funcs = {
{ "__tostring", LI_MyType__tostring },
};
int LC_MyType_newInstance(lua_State* L) {
auto userdata = static_cast<MyType*>(lua_newuserdata(L, sizeof(MyType)));
new(userdata) MyType();
// Create the metatable
lua_createtable(L, 0, funcs.size()); // |userdata|table|
lua_pushvalue(L, -2); // |userdata|table|userdata|
luaL_setfuncs(L, funcs.data(), 1); // |userdata|table|
lua_setmetatable(L, -2); // |userdata|
return 1;
}
int LI_MyType__tostring(lua_State* L) {
// NOTE: …Run Code Online (Sandbox Code Playgroud) 如何#在Lua中更改表的长度operator(),手册建议__len在metatable中分配函数,然后将metatable分配给我想要覆盖的表,但是这不能按预期工作?我没有选择在C端覆盖它.
turtles = {1,2,3}
setmetatable(turtles, {__len = function(mytable) return 5 end})
print(#turtles)
--returns 3, should return 5
Run Code Online (Sandbox Code Playgroud) 昨天我和Lua搞混乱,偶然发现了'newproxy'功能.
http://wiki.roblox.com/index.php?title=Function_dump/Basic_functions#newproxy
我有点理解它,但我不确定它是如何有用的.我知道它会创建一个附加了元表的空白userdata对象(如果参数为true).
newproxy如何有用?这是我在搞乱它时所做的一个例子:
local proxy = newproxy(true)
local metatable = getmetatable(proxy)
metatable.__index = function(array, key) print(array, key) end
local y = proxy[100]
--[[
OUTPUT:
userdata: 0x443ad4b4 100
]]
Run Code Online (Sandbox Code Playgroud) 所以我创建了一个所有字符串都可以使用的函数,它被称为append。
local strmt = getmetatable("")
function strmt.__index.append(self, str)
self = self..str
return self
end
Run Code Online (Sandbox Code Playgroud)
然后该函数的使用方式如下:
self = self:append("stuff")
Run Code Online (Sandbox Code Playgroud)
有没有办法创建一个函数来执行此操作:
local stuff = "hi "
stuff:append("bye")
print(stuff)
Run Code Online (Sandbox Code Playgroud)
并生产
hi bye
Run Code Online (Sandbox Code Playgroud)