4

我正在使用 Lua 5.2,为了这个问题,假设这些表专门用作数组。

这是一个返回数组尾部的函数(数组减去它的第一个元素):

function tail(t)

   if # t <= 1 then
      return nil
   end

   local newtable = {}
   for i, v in ipairs(t) do
      if i > 1 then
          table.insert(newtable, v)
      end
   end

   return newtable
end 

例如:

提示> table.concat(tail({10, 23, 8}), ", ")

23、8

然而,这是通过返回表的新副本来实现的。有没有办法避免创建新表?

我正在寻找相当于 C 的返回指向下一个元素 ( t++) 的指针。可能吗?

4

5 回答 5

9

如前所述,这通常是不可能的。

但是,使用元表,您可以通过引用原始表来实现一个tail功能,该功能无需复制所有数据即可执行您想要的操作。以下适用于 Lua 5.2 中的大多数操作,但例如不适用于:table.concat

function tail(t)
  return setmetatable({}, {
    __index = function(_, k) return t[k+1] end,
    __newindex = function(_, k, v) t[k+1] = v end,
    __len = function(_) return #t-1 end,
    __ipairs = function(_) return 
      function(_, i)
        if i+1==#t then return nil end
        return i+1, t[i+2] end, 
      t, 0 end,
    __pairs = function(t) return ipairs(t) end,
  })
end
于 2012-09-11T15:53:51.183 回答
5

这是我所知道的实现tail() 的最好方法。它制作了一张新桌子,但我认为这是无法避免的。

function tail(list)
    return { select(2, unpack(list)) }
end
于 2013-02-11T11:09:43.373 回答
3

Nicol 是正确的,您不能引用数组的切片,但是有一种更简单/更短的方法来做您想做的事情:

function tail(t)
  local function helper(head, ...) return #{...} > 0 and {...} or nil end
  return helper((table.unpack or unpack)(t))
end

print(table.concat(tail({10, 23, 8}), ", "))然后将打印23,8.

(添加table.unpack or unpack使其也适用于 Lua 5.2)

于 2012-09-11T15:50:48.267 回答
2

我正在寻找相当于 C 的返回指向下一个元素 (t++) 的指针。可能吗?

不,您想要这样做的唯一可能原因是性能。这种特性只在低级编程语言中发现。Lua 是一种脚本语言:性能并不是实现它的优先级。

只需像您正在做的那样制作另一个表格,或用于table.remove修改原始表格。哪个最适合您。请记住:像表和用户数据这样的大而重要的对象在 Lua 中都是通过引用存储的,而不是按值存储的。

于 2012-09-11T15:16:51.863 回答
1

prapin 的建议是使用元表来呈现序列的视图,这大致是我的做法。一个可能有帮助的抽象是为定义一个元表,它可以是一个 0 元函数,它返回一对表和一个偏移索引——我们在这里只使用函数来表示元组。然后我们可以定义一个元表,使这个函数表现得像一个表:

do
  local tail_mt = {
    __index = function(f, k) local t, i=f(); return t[k+i] end,
    __newindex = function(f, k, v) local t,i=f(); t[k+1] = v end,
    __len = function(f) local t,i=f(); return #t-i end,
    __ipairs = function(f) 
      local t,i = f () 
      return
        function (_, j)
          if i+j>=#t then 
            return nil
          else
            return j+1, t[i+j+1] 
          end
        end, nil, 0 
      end,
  }
  tail_mt.__pairs = tail_mt.__ipairs -- prapin collapsed this functionality, so I do too

  function tail (t)
    if type(t) == "table" then
      return setmetatable ( function () return t, 1 end, tail_mt )
    elseif type(t) == "function" then
      local t1, i = t ()
      return setmetatable ( function () return t1, i+1 end, tail_mt )
    end
  end
end

使用 __index 和 __newindex 元方法,您可以编写 f[2]=f[1]+1 等代码。

尽管这个(未经测试的)代码不会无休止地创建一次性元表,但它可能不如 prapin 的有效,因为它将调用 thunk(0 元函数)来获取它们的内容。但是,如果您可能对扩展功能感兴趣,比如对序列有更一般的看法,我认为这更灵活一些。

于 2012-09-12T12:21:03.527 回答