提问人:szulak 提问时间:9/21/2023 更新时间:9/22/2023 访问量:62
Lua 中的自定义 foreach 实现
Custom foreach implementation in Lua
问:
我正在尝试实现一个自定义迭代器,它的工作方式类似于 Lua,但以更“语法友好”的方式。我遇到了以下构造(不确定它是纯粹在 Lua 中完成的,还是在 Lua 源代码中的某种 C“hack”中完成的。table.foreach
-- creature is a collection of Creature objects
-- "ps" is used as a filter variable
foreach creature cre "ps" do
if cre.name ~= $name then
-- code...
end
end
我尝试使用 ,依此类推 - 但无法获得与上述代码示例类似的结果。你能给我一个提示,如何实现吗?table.foreach
ipairs
答:
1赞
Oka
9/22/2023
#1
新关键字需要 preproccesor 或直接修改语言的语法。
通过编写迭代器,已经可以很容易地实现这种语法的近似,而无需离开语言的限制 - 一个函数,当提供给泛型时,它会持续提供循环变量的值,直到它返回的第一个值为零。
(更具体地说,您通常会编写一个函数来创建(返回)迭代器。pairs
和 ipairs
就是这方面的例子。)
Next
是一个函数,当提供表和键时,返回下一个键及其关联值。
您可以使用元表和元方法扩展它,以缩短构造迭代器所需的语法(Lua 中正确构造的类/对象/原型(即 OOP)已经严重依赖元表)。__call
所有这些都意味着语法
for value in collection 'filter' do
print(value)
end
是非常可以实现的。
完整的示例,带有一个非常基本的迭代器:
-- This is a live, proxied view into an existing table
local function View(t)
local methods = {}
local function match(value, filter)
return type(value) == 'string' and value:match(filter)
end
function methods:filter(filter)
local key, value
return function (_)
repeat
key, value = next(t, key)
until value == nil or match(value, filter)
return value, key
end
end
return setmetatable({}, {
__index = methods,
__metatable = false,
__call = methods.filter
})
end
local foo = View { 'c', 'a', 'b', 'a', 'c', 'd' }
-- :filter via __call
for value in foo '[ab]' do
print(value)
end
print('-------')
-- explicitly
for value in foo:filter '[cd]' do
print(value)
end
print('-------')
-- additional index variable
-- this is the inverse of the more typical `pairs` construct
for value, key in foo '[ad]' do
print(key)
end
a
b
a
-------
c
c
d
-------
2
4
6
评论
0赞
ESkri
9/22/2023
实现只读是一种快速而肮脏的方法吗?__newindex = false
0赞
Oka
9/22/2023
呃,有点 - 如果您尝试在该表:)中注册一个新索引,运行时将爆炸。 绕过它。示例的那部分并不重要,但我的意思可能是无法通过代理/视图 () 更改/引用。我将更新措辞,因为它不完全是只读的。rawset
__metatable = false
methods
getametatable
评论
foreach
for cre in creature:filter"ps" do ... end