我能否强制Lua的表格索引从零开始?

17

我有一个关于 Lua 的问题。它使用基于1的索引。语言具有在索引0处设置值的功能,但该值不会被计算为表长度的一部分,并且字符串操作仍然是基于1的。因此,我认为这个功能是特殊的,而不是与索引有关。

我不想争论基于1或基于0的问题。我只是想知道是否有一种强制使用基于0的索引的方法。


1
我能问一下为什么这是个问题吗?好的,你更喜欢从0开始索引,但是为什么不能使用从1开始索引呢? - gnud
5
我也遇到了这个问题 :) 不管是什么情况,在Lua中我几乎每次都搞错了。我已经习惯于使用从零开始的其他语言,以至于我的Lua代码只因为这一个问题就充满了错误! - jcoder
我认为没有任何标志可以将Lua从1切换到0,因此除了修改Lua(需要使用非标准Lua,我在这里称之为Lua0),我不知道该怎么做。 - Dan D.
@gnud 这显然是个问题,因为这是 C 脚本而不是 XPath 脚本。当然我可以使用从 1 开始的索引,但这对我来说效率太低了,因为我很笨,同时使用双重索引系统让我感到困难。(我必须使用 C 来进行主机系统)而且任何在脚本和主机之间交换的索引数据都必须进行翻译。我可以肯定这会导致更多的错误,这让我更难以处理。 - eonil
2
@Judge 我认为这是不同的问题,因为我问的是改变语言默认行为的方法,而这个问题是在问语言设计的合理原因。 - eonil
显示剩余2条评论
10个回答

9
使用以0为索引的数组实际上非常简单:
local array={
[0]="zero",
    "one",
    "two"
}

for i=0,#array do
    print(array[i])
end

你可以使用#array而不需要减去1,因为长度操作符实际上返回的是最高索引(技术上来说,是第一个nil之前的键),而不是实际的“长度”(在Lua中也没有意义)。

对于字符串操作符,你可能只需要创建重复的函数(虽然可能有更好的方法)

ipairs()也只支持1个索引,所以你将不得不定义自己的函数或者只是使用常规的for语句。


4

我知道这个问题已经有1年的历史了,但我认为未来的寻求者会对这个事实感兴趣,即CFF Explorer包含一个脚本语言(Lua带有补丁),其中有0索引表修补程序:

http://www.ntcore.com/files/cffscriptv2.htm

此外,在上面的文档中,作者表示他不得不禁用大多数标准库函数,因为它们与从0开始索引的数组不兼容,请再阐述一下您对这个问题的思考过程 :)

3
直接的答案是:修改Lua源代码。将所有对Lua table 的操作改为基于0。
我正在进行此操作,并包括Lua标准库。可提供Windows二进制文件。 http://lua-users.org/wiki/CountingFromOne(底部有一些注释) https://github.com/farteryhr/lua-base-0(请查看提交历史记录以了解已修改内容)
大多数都是关于+1 -1的繁琐工作,其中大部分已完成。
请编写一些测试用例(尽可能涵盖语言的许多细节)并报告错误。
(目前已知metatable还有问题,但我找不到时间去调查它)

1
这并没有回答问题。一旦您拥有足够的声望,您将能够评论任何帖子;相反,提供不需要询问者澄清的答案。- 来自审核 - Dave
@Dave 感谢您的建议,我已经添加了直接的答案,请考虑撤销负评。 - Farter Yang
我的评论与对答案的投票无关。无法确定是谁投了票。 - Dave
也许,我的意思是,建议删除的评论? - Farter Yang

2
我认为Lua已经具备您需要的0-based功能。不幸的是,我提到的功能是Lua的开源许可证。
我无法找到一个补丁或分支,可以改变语言中1-based的特性。
不幸的是,将Lua分支以使其变为0-based也会破坏向后兼容性。失去所有当前的插件模块可能是为了使用方便而付出的太大代价。

似乎没有简单的方法可以覆盖这种行为。 - eonil

2

对于ponzao的回答,Eonil提到:真正的问题在于基础语言应该是C语言,这是一种从0开始进行索引的语言。在脚本和宿主之间交换索引数据时,必须正确翻译。

如果你想将C语言数据结构暴露给Lua,可以使用userdata将它们打包起来。你可以使用元表使索引行为按照自己的意愿进行。这样,就可以确保正确的翻译。


1

一种有缺陷的不良方法:

function zeroIndexed(tbl)
    local mt = {}
    mt.data = tbl
    mt.__index = function(t, k)
        return mt.data[(type(k) == "number" and k + 1 or k)]
    end
    mt.__newindex = function(t, k, v)
        mt.data[(type(k) == "number" and k + 1 or k)] = v
    end
    mt.__len = function()
        return #mt.data
    end
    return setmetatable({}, mt)
end
t = zeroIndexed({5, 6, 7})
print(t[0], t[1], t[2])
t[0] = 4
print(t[0], #t)
t[#t] = 8
print(t[#t - 1], #t)

Lua 5.2 输出:
5       6       7
4       3
8       4

在 Lua 5.1 中,#t 返回 0,因为对于表和字符串,不尊重 __len元方法。但要记住,table.insert 和其他表方法将不再起作用,因为插入现在是通过 t[#t] = x 完成的。我不建议使用这种方法。

为什么你不推荐在表插入问题中使用它? - Daniel Sperry
这个有一个问题:ipairs 和 pairs 迭代器仍会返回基于 1 的数组的索引。 - val is still with Monica

1

即使在Lua源代码中有#define TABLE_START_INDEX 1(我不相信会有),如果你改变了这个值,你基本上会自己给自己惹麻烦。这是因为大多数库都使用基于1的索引。因此,任何执行以下操作的代码都将出现问题。

for i = 1, #t do ... end

当然,您可以使用迭代器甚至创建帮助函数来避免这种情况。

function get_first(t) return t[1] end

但是,您尝试解决的实际问题可能比从0到1的索引更难。


4
不是的,这不是一个真正的问题。真正的问题是基础语言应该是C语言,它是一个以0为起始索引的语言。在脚本和主机之间交换数据时,必须正确翻译索引。而且我必须一直处理双重索引系统。 - eonil

0

您可以通过使用一个能够识别不同索引基础的迭代器来修复这个 Lua 缺陷:

function iarray(a)
  local n = 0
  local s = #a
  if a[0] ~= nil then
    n = -1
  end
  return function()
    n = n + 1
    if n <= s then return n,a[n] end
  end
end

然而,您仍需手动添加第零个元素:

使用示例:

myArray = {1,2,3,4,5}
myArray[0] = 0
for _,e in iarray(myArray) do
  -- do something with element e
end

-3

我发现当与一个从0开始索引的语言(例如C)进行接口时,最好不要使用索引0。虽然这会浪费一些内存,但改变Lua的方式相当荒谬。


-3

你的问题的答案是否定的,目前我所知道的是没有办法强制所有Lua处理的过程都使用索引0,因为#table从1到“n”,没有索引0就几乎没用了,但这取决于你想做什么,你可以比较两个表格,一个读取产品,一个读取收入,如果产品增加了,你就有更多了,如果产品等于1,那么你就没有了,所以你只需要读取一个表格,而不是两个,希望我表达清楚了。<,<


网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接