Lua: 用 nil 解压?选择?
Lua: Unpack with nil? Alternative?
我已经 运行 进入了 unpack bug 时代,我在 Lua 中有一个数组可以包含 nil 值,我想用 nil 解压数组价值观;这似乎是不可能的。这个逻辑的替代方案是什么?
这是我尝试使用的代码 运行
function InputSystem:poll(name, ...)
local system = self:findComponent(name)
local values, arr = {...}, {}
for i, v in pairs(values) do
arr[#arr+1] = system[v]
end
--If the first guy is null this does not work!! WHY
return unpack(arr, 1, table.maxn(values))
end
我的想法是动态轮询我的输入系统,这样我就只 return 我想要的值,如下所示:
local dragged,clicked,scrolled = self.SystemManager:findSystem('Input'):poll('Mouse', 'Dragged', 'Clicked', 'Scrolled')
有什么想法吗?谢谢
编辑:
我好像没完全理解Lua。我想要 return 与 ... 传入的变量数量相同,但是在循环中如果找不到 属性 我认为它会将其设置为 nil,但这似乎是错了。
function InputSystem:poll(name, ...)
local system = self:findComponent(name)
local values, arr = {...}, {}
for i, v in pairs(values) do
arr[#arr+1] = system[v] --If not found set nil
end
--I want this to return the length of ... in variables
--Example I pass 'Dragged', 'Clicked' I would want it to return nil {x:1,y:1}
return unpack(arr, 1, table.maxn(values))
end
明明我是Lua高手...
您应该使用 table.pack
和 table.unpack
来保留 nil
。如果您使用 Lua 5.2 或更高版本,您可以删除兼容性代码段。
-- Backwards compatibility
table.pack = table.pack or function(...) return { n = select("#", ...), ... } end
table.unpack = table.unpack or unpack
function test(...)
local values = table.pack(...)
local arr = {}
for i, v in pairs(values) do
-- iterates only the non-nil fields of "values"
arr[i] = 10*v
end
return table.unpack(arr, 1, values.n)
end
print(test(nil, 1, nil, 2, nil, nil, 3))
$ lua5.3 test.lua
nil 10 nil 20 nil nil 30
$ lua5.2 test.lua
nil 10 nil 20 nil nil 30
$ lua5.1 test.lua
nil 10 nil 20 nil nil 30
$ luajit test.lua
nil 10 nil 20 nil nil 30
for i, v in pairs(values) do
arr[#arr+1] = system[v] -- This doesn't work!
end
您的实现的问题是您希望将 nil 附加到数组以增加它的长度,但事实并非如此:
local arr = {1, 2, 3}
print(#arr) --> 3
arr[#arr+1]=nil
print(#arr) --> 3
本质上,您想要的是一个 map
函数,它接受一个元素列表,对每个元素应用一个函数 fn
,然后 returns 列表结果。
通常,这可以很容易地实现为 tail-recursive 函数,如下所示:
local function map(fn, elem, ...)
if elem then return fn(elem), map(fn, ...)
end
虽然这不能很好地处理 nil
个参数,因为它们会使条件为假,但仍有参数需要处理,但我们可以使用 select
修改它以避免这种情况:
local function map(fn, elem, ...)
if select('#', ...)>0 then return fn(elem), map(fn, ...)
else return fn(elem) end
end
-- This implementation still gets TCOd :)
然后你可以这样使用它:
map(string.upper, 'hello', 'world') --> 'HELLO', 'WORLD'
您想将 ...
中的每个值映射到 table 中的相应值,但是由于 map
将函数作为其第一个值,我们可以将其包装在一个功能。由于在编写代码时我们不知道 table,因此我们必须在运行时生成函数:
local function index(table)
return function(idx)
return table[idx]
end
end
现在我们可以这样做了:
map(index{'hello', 'world'}, 1, 2) --> 'hello', 'world'
-- index{'hello', 'world'} returns a function that indexes the given table
-- with its first argument and returns the value
然后你可以这样写你的InputSystem
函数:
function InputSystem:poll(name, ...)
return map(index(self:findComponent(name)), ...)
end
显然,在这种情况下我们不需要通用映射函数,因为我们总是索引 table。我们可以像这样重写 map 以使用 table:
local function map(tab, elem, ...)
if select('#', ...)>0 then return tab[elem], map(tab, ...)
else return tab[elem] end
end
主要功能将变为:
function InputSystem:poll(name, ...)
return map(self:findComponent(name), ...)
end
我还注意到一件事:
for i, v in pairs(values) do
arr[#arr+1] = system[v] --If not found set nil
end
pairs
乱序迭代,因此您的行 for i, v in pairs(values) do
很可能会完全重新排序这些值。因为你写 local dragged,clicked,scrolled = self.SystemManager:findSystem...
我相信你希望 return 值保持有序。
我已经 运行 进入了 unpack bug 时代,我在 Lua 中有一个数组可以包含 nil 值,我想用 nil 解压数组价值观;这似乎是不可能的。这个逻辑的替代方案是什么?
这是我尝试使用的代码 运行
function InputSystem:poll(name, ...)
local system = self:findComponent(name)
local values, arr = {...}, {}
for i, v in pairs(values) do
arr[#arr+1] = system[v]
end
--If the first guy is null this does not work!! WHY
return unpack(arr, 1, table.maxn(values))
end
我的想法是动态轮询我的输入系统,这样我就只 return 我想要的值,如下所示:
local dragged,clicked,scrolled = self.SystemManager:findSystem('Input'):poll('Mouse', 'Dragged', 'Clicked', 'Scrolled')
有什么想法吗?谢谢
编辑:
我好像没完全理解Lua。我想要 return 与 ... 传入的变量数量相同,但是在循环中如果找不到 属性 我认为它会将其设置为 nil,但这似乎是错了。
function InputSystem:poll(name, ...)
local system = self:findComponent(name)
local values, arr = {...}, {}
for i, v in pairs(values) do
arr[#arr+1] = system[v] --If not found set nil
end
--I want this to return the length of ... in variables
--Example I pass 'Dragged', 'Clicked' I would want it to return nil {x:1,y:1}
return unpack(arr, 1, table.maxn(values))
end
明明我是Lua高手...
您应该使用 table.pack
和 table.unpack
来保留 nil
。如果您使用 Lua 5.2 或更高版本,您可以删除兼容性代码段。
-- Backwards compatibility
table.pack = table.pack or function(...) return { n = select("#", ...), ... } end
table.unpack = table.unpack or unpack
function test(...)
local values = table.pack(...)
local arr = {}
for i, v in pairs(values) do
-- iterates only the non-nil fields of "values"
arr[i] = 10*v
end
return table.unpack(arr, 1, values.n)
end
print(test(nil, 1, nil, 2, nil, nil, 3))
$ lua5.3 test.lua
nil 10 nil 20 nil nil 30
$ lua5.2 test.lua
nil 10 nil 20 nil nil 30
$ lua5.1 test.lua
nil 10 nil 20 nil nil 30
$ luajit test.lua
nil 10 nil 20 nil nil 30
for i, v in pairs(values) do
arr[#arr+1] = system[v] -- This doesn't work!
end
您的实现的问题是您希望将 nil 附加到数组以增加它的长度,但事实并非如此:
local arr = {1, 2, 3}
print(#arr) --> 3
arr[#arr+1]=nil
print(#arr) --> 3
本质上,您想要的是一个 map
函数,它接受一个元素列表,对每个元素应用一个函数 fn
,然后 returns 列表结果。
通常,这可以很容易地实现为 tail-recursive 函数,如下所示:
local function map(fn, elem, ...)
if elem then return fn(elem), map(fn, ...)
end
虽然这不能很好地处理 nil
个参数,因为它们会使条件为假,但仍有参数需要处理,但我们可以使用 select
修改它以避免这种情况:
local function map(fn, elem, ...)
if select('#', ...)>0 then return fn(elem), map(fn, ...)
else return fn(elem) end
end
-- This implementation still gets TCOd :)
然后你可以这样使用它:
map(string.upper, 'hello', 'world') --> 'HELLO', 'WORLD'
您想将 ...
中的每个值映射到 table 中的相应值,但是由于 map
将函数作为其第一个值,我们可以将其包装在一个功能。由于在编写代码时我们不知道 table,因此我们必须在运行时生成函数:
local function index(table)
return function(idx)
return table[idx]
end
end
现在我们可以这样做了:
map(index{'hello', 'world'}, 1, 2) --> 'hello', 'world'
-- index{'hello', 'world'} returns a function that indexes the given table
-- with its first argument and returns the value
然后你可以这样写你的InputSystem
函数:
function InputSystem:poll(name, ...)
return map(index(self:findComponent(name)), ...)
end
显然,在这种情况下我们不需要通用映射函数,因为我们总是索引 table。我们可以像这样重写 map 以使用 table:
local function map(tab, elem, ...)
if select('#', ...)>0 then return tab[elem], map(tab, ...)
else return tab[elem] end
end
主要功能将变为:
function InputSystem:poll(name, ...)
return map(self:findComponent(name), ...)
end
我还注意到一件事:
for i, v in pairs(values) do
arr[#arr+1] = system[v] --If not found set nil
end
pairs
乱序迭代,因此您的行 for i, v in pairs(values) do
很可能会完全重新排序这些值。因为你写 local dragged,clicked,scrolled = self.SystemManager:findSystem...
我相信你希望 return 值保持有序。