【问题标题】:Lua: Unpack with nil? Alternative?Lua:用 nil 解压?选择?
【发布时间】:2023-03-04 16:43:01
【问题描述】:

我遇到了古老的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

我的想法是我动态地轮询我的输入系统,以便我只返回我想要的值:

local dragged,clicked,scrolled = self.SystemManager:findSystem('Input'):poll('Mouse', 'Dragged', 'Clicked', 'Scrolled')

有什么想法吗?谢谢

编辑:

我似乎没有完全理解 Lua。我想返回与 ... 传入的相同数量的变量,但是在循环中如果找不到该属性,我认为它会将其设置为 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 大师...

【问题讨论】:

  • 一个没有被指定做你想做的事情的函数不会让它出错......
  • @Deduplicator 我不是那个意思,我是在引用以前的帖子时遇到同样的问题。是我的逻辑错了。

标签: lua love2d


【解决方案1】:

您应该使用table.packtable.unpack 来保留nils。如果您使用 Lua 5.2 或更高版本,则可以删除兼容性 sn-p。

-- 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

【讨论】:

  • @henri-menke 感谢您的回复!我似乎还没有完全理解我的问题,并编辑了我的问题。
  • @GrizzlyEnglish arr[i] = system[v]
  • @HenriMenke 我也想指出这一点,但是您会注意到使用了pairs,而不是ipairs,因此无论如何顺序都搞砸了。仅将其更改为 ipairs 不是一种选择,因为它只为序列定义。
  • @DarkWiiPlayer 不,订单很好。请参阅我的答案中的更新示例。
  • @HenriMenke 有了您的评论和 DarkWiiPlayer,我知道我试图增加索引不适用于 nils。我标记了 DarkWiiPlayers 答案,因为它帮助我更好地理解了一点。不过谢谢你的帮助!
【解决方案2】:
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 应用于每个元素并返回结果列表。

通常,这可以很容易地实现为 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'

您希望将... 中的每个值映射到表中的相应值,但由于map 将函数作为其第一个值,我们可以将其包装在函数中。而且由于在编写代码时我们不知道该表,因此我们必须在运行时生成该函数:

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

显然,在这种情况下,我们不需要通用的 map 函数,因为我们总是在索引一个表。我们可以重写 map 来使用这样的表:

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...,我相信您希望返回值保持有序。

【讨论】:

  • 哇。谢谢你的回答!对我来说最大的收获是我没有理解将 nil 附加到表不会增加索引的想法(这可能很明显,但我没有得到它。)因此,映射遍历并递归返回每个属性桌子。我不知道你可以做这样的多重回报。再次感谢!
  • 地图函数在 else 子句后缺少一个结尾,我试图编辑它,它不会让我。不知道这是否重要,只是想我会指出来。
  • @GrizzlyEnglish 已修复 :)
  • 不能解决unpackNotDoingTheRightThing™ 的具体问题。提供一种对大多数面临 AsStated® 问题的人来说无用的解决方法,并搜索潜在的解决方案。 “XY问题问题”的教科书示例。
  • @SzczepanHołyszewski 我同意这是一个 XY 问题。 OP想要一件事,又问另一件事;我尽力为实际问题提供解决方案。
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 2012-07-09
  • 1970-01-01
  • 2013-12-21
  • 2012-07-21
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多