为啥 Lua 数组(表)从 1 而不是 0 开始?

Posted

技术标签:

【中文标题】为啥 Lua 数组(表)从 1 而不是 0 开始?【英文标题】:Why do Lua arrays(tables) start at 1 instead of 0?为什么 Lua 数组(表)从 1 而不是 0 开始? 【发布时间】:2011-02-16 15:51:38 【问题描述】:

我不明白这部分 Lua 的决定背后的基本原理。为什么索引从 1 开始?我已经阅读(和其他许多人一样)this great paper。在我看来,这是一种学习和编程非常愉快的语言的一个奇怪角落。不要误会我的意思,Lua 很棒,但必须在某个地方做出解释。我发现的大部分内容(在网络上)只是说索引从 1 开始。句号。

阅读它的设计师对这个主题的看法会很有趣。

请注意,我是 Lua 的“非常”初学者,我希望我不会遗漏一些关于表的明显内容。

【问题讨论】:

默认范围也是全局的。 Lua 的两个最大错误。 我不会把从 1 开始的功能称为错误。它实际上更有意义 - 程序员受过良好的训练,可以从我们不喜欢的其他语言中考虑基于 0 的索引。我们也被训练去思考 5/2 = 2。这并不正确。 @BlueRaja-DannyPflughoeft:没有。零索引更有意义——人类在从 1 开始计数方面训练有素,以至于以 0 开头的语言最初会令人困惑。但我很想在这里向您推荐 Edsger Dijkstra:cs.utexas.edu/users/EWD/ewd08xx/EWD831.PDF @nightcracker:当你数桌子上的苹果时,你把第一个算作“一”,第二个算作“二”,依此类推。没有人算第一个一为“零”,然后在末尾加一;从零开始计数显然是违反直觉的。是的,我意识到这就是索引在内部的工作方式,但这就是我们称之为抽象的原因。 我从不理解对基于 0 的索引的所有热爱。偏移量(从一开始要跳过多少项?)和子序列(0 ≤ x 【参考方案1】:

Lua 源自 Sol,这是一种专为石油工程师设计的语言,没有接受过正式的计算机编程培训。没有受过计算机培训的人认为从零开始计数是非常奇怪的。通过采用基于 1 的数组和字符串索引,Lua 设计人员避免了混淆他们的第一批客户和赞助商的期望。

虽然一开始我也觉得它们很奇怪,但我已经学会了喜欢从 0 开始的数组。但是我对 Lua 的基于 1 的数组感到满意,尤其是 使用 Lua 的通用 for 循环和 ipairs 运算符——我通常可以避免担心数组的索引方式。

【讨论】:

这只是一个历史的营销原因。没有合理的理由,尤其是在当前。而且似乎您甚至试图避免基于 1 的索引而不是使用它:) @Eonil 实际上避免显式索引减少了索引错误。 @Eonil 历史原因通常是相关的。你从一些东西开始,然后你永远不能改变它,因为它会破坏所有现有的代码。对于 0 与 1 索引尤其不利,因为它的中断方式非常微妙。 区别在于从 1 到 Length 和从 0 到 -1,但在 for 循环中,< length 在“基于 0 的怪异语言”上更方便且更易于阅读”。我承认当我看到一个从 1 开始迭代的循环时,我立即假设它从第二个元素开始:S 当我开始将它作为一个名为 ComputerCraft 的 Minecraft 模组的一部分时,我认为这是最愚蠢的事情,但鉴于历史先例,我想我可以理解为什么会这样。也就是说,您是否有一个方便的链接,我可以在其中阅读有关与 Sol 的连接的更多信息?我总是对我正在使用的一种语言的背景感到好奇,即使我没有将它用于任何严肃的事情。【参考方案2】:

Lua 中的编程第一次讨论表时,他们提到:

由于您可以使用任何值对表进行索引,因此您可以使用任何您喜欢的数字来开始数组的索引。然而,在 Lua 中习惯以 1 开始数组(而不是像在 C 中那样以 0 开始),并且一些工具坚持这个约定。

稍后,在有关数据结构的章节中,他们又说了几乎相同的话:Lua 的内置工具假定基于 1 的索引。

无论如何,使用基于 1 的索引有 一对 的便利。即#(长度)运算符:t[#t]访问表的最后一个(数字)索引,t[#t+1]访问最后一个索引过去。对于尚未接触过基于 0 的索引的人来说,#t+1 会更直观地移动到列表末尾。还有 Lua 的 for i = 1,#t 构造,我认为它与前一点属于同一类别,即“1 到长度”比索引“0 到长度减 1”更明智。

但是,如果你不能打破基于 0 的索引的思维方式,那么 Lua 的基于 1 的索引肯定会成为更大的障碍。最终,作者想要一些适合他们的东西;我承认我不知道他们最初的目标是什么,但从那以后它可能已经改变了。

【讨论】:

【参考方案3】:

我的理解是,之所以这样,只是因为作者认为这样做是一种好方法,而在他们将语言发布给公众之后,这个决定就变得相当僵化了。 (我怀疑如果他们今天改变它,将会付出惨痛的代价!)除此之外,我从未见过任何特别的理由。

【讨论】:

可能的理由:C 这样做只是因为数组基本上只是一个指针和array[0] == array + 0;,当数组实际上是一个哈希表时,从 1 开始的计数更自然。 Lua 索引实际上是索引。在 C 中,当您说索引时,您真正的意思是偏移量。【参考方案4】:

也许是不太重要的一点,但我还没有听说过:字符串中的第一个和最后一个字符分别位于 1 和 -1,而不是 0 和 -1,这具有更好的对称性。

【讨论】:

虽然这很好,但它不是从 1 开始的原因。 这不是更好的对称性。现在您遇到的情况是 -3、-2、-1、1、2 和 3 是有效索引,但不是 0! 对称性不是更好吗?仅仅因为一个索引完全无效(不指向任何一端,我同意这不是很好,如果你碰巧需要每个索引达到整数限制......不管那是 Lua 的)并不意味着对称性不存在【参考方案5】:

Lua 库更喜欢使用从 1 开始的索引。但是,您可以使用任何您想要的索引。你可以用0,你可以用1,你可以用-5。它甚至在他们的手册中,可以在 (https://www.lua.org/pil/11.1.html) 找到。

事实上,这里很酷的是内部 lua 库会将一些传递的 0 视为 1。使用 ipairs 时要小心。 所以:("abc"):sub(0,1) == "a" and ("abc"):sub(1,1) == "a" 将是真的。

 You can start an array at index 0, 1, or any other value:

-- creates an array with indices from -5 to 5
a = 
for i=-5, 5 do
  a[i] = 0
end

【讨论】:

有没有办法让('a', 'b')[1] 评估为'b' 而不是'a'?这对我来说似乎是内置的。 ([0] = 'a', 'b')[1]【参考方案6】:

C和Lua中数组索引的具体定义不同。

在C数组中,表示:数组地址的项地址偏移量

在 Lua 数组中,表示:数组中的第 n 项

为什么大多数语言都使用从 0 开始的索引?因为带有offset definition的编译代码更方便有效。他们主要处理地址。

还有 Lua。这是 lua 5.3.5 的 C 表索引代码:

const TValue *luaH_getint (Table *t, lua_Integer key) 
  if (l_castS2U(key) - 1 < t->sizearray)
    return &t->array[key - 1];
  else 
    Node *n = hashint(t, key);
    for (;;) 
      if (ttisinteger(gkey(n)) && ivalue(gkey(n)) == key)
        return gval(n);
      else 
        int nx = gnext(n);
        if (nx == 0) break;
        n += nx;
      
    
    return luaO_nilobject;
  

我们应该关注代码&amp;t-&gt;array[key - 1],它有一个减法运算。与从0开始的索引相比,效果不佳。

但是,从 1 开始的索引更接近人类语言。我们更关注英文、中文、日文等的第 n 项。

所以,我猜Lua的设计者选择了从1开始的索引,他们选择了易于理解的纯新程序,放弃了便利性和有效性。

【讨论】:

【参考方案7】:

真正的原因是该语言是葡萄牙法律中定义的实现,主要开发中心位于巴西,他们的偏好是避免使用零或空或无作为索引或下标。但是,在某些版本中,该语言确实允许在表创建函数中使用 1 以外的起始索引。

【讨论】:

即使这是真的,它与 Lua 的设计方式完全无关。 是的,不,这个答案非常可疑。请提供有关葡萄牙法律体系的声明的来源,因为它与 Lua 相关,因为我什至还没有接近看到和理解相关性。【参考方案8】:

在您的示例中,table[0]总是返回 nil(null)除非您将值分配给它自己,像table[0] = 'some value' 然后table[0] 将返回'some value',这是你分配的。

这是一个例子:

tbl = "some"
print("tbl[0]=" .. tostring(tbl[0]))
print("tbl[1]=" .. tostring(tbl[1]))
nothing = 
print("nothing[0]=" .. tostring(nothing[0]))
print("nothing[1]=" .. tostring(nothing[1]))
nothing[0] = "hey"
print("(after assign)\nnothing[0]=" .. tostring(nothing[0]))

【讨论】:

【参考方案9】:

这对每个人来说都是有意义的,如果

table = 

table 为空。那么,当

table == something

该表包含一些内容,所以它包含的是table 中的索引 1,如果您知道我的意思的话。

我的意思是table[0]存在,它的table = 是空的,现在程序员不会调用一个空表,它设置它们,然后填充它,找到一个没有用的每次你想调用它时都是空表,所以创建一个空表更简单。

我的英语不会变得更好,这是我最好的语法。 如果您不喜欢它,您可以不继续阅读它,但是为试图帮助的人提供 -rep 会使人们根本不想提供帮助,尤其是对于语法之类的东西。 我是一个数字和变量,而不是语法的人。对不起。

【讨论】:

我不明白表的值为 0 的概念。表的长度可以为 0。但这与第一个索引的选择无关。我不在乎小的语法错误,但我根本不明白你回答的重点,这就是我投反对票的原因。 这就是我所说的,一个表不能用 0 索引或值来保存,因为我们将它用作一个空表 使用索引0 作为唯一元素的数组仍然不为空。事实上 lua 支持这一点,它只是不是默认约定。 是的,我同意你的观点,在其他一些语言上,但不是 lua,lua 索引 0 不存在,所以我们可以想象它像一个空 = 0,或者我就是这样想象它,即使你可以强制索引为0,它不会与表值一起使用#table不会读取0索引,所以我的回答仍然是lua它基本上像一个常规事件一样,现在如果他们打算这样做与你无关不会再写漏洞代码,我们对此无能为力:/,我仍然相信公平地说,在 lua 中,空表的索引为 0 我不认为你在语法上得到了否定的代表。人们可以很容易地进行编辑以帮助您修复。问题是您的答案似乎并不连贯,即使在其意图上也是如此。表的长度与第一个索引的选择有什么关系?这似乎是你的全部论点:它的长度等于它的最后一个索引?如果你回到 SO,你应该再看看这个。我相信10年后你会明白为什么每个人都如此努力。有时我想为我 5 年前给出的答案而自责,所以......是的

以上是关于为啥 Lua 数组(表)从 1 而不是 0 开始?的主要内容,如果未能解决你的问题,请参考以下文章

在lua表中实现索引从0开始

PLPGSQL 数组索引从 1 开始?

在servicestack中使用protobuf,为啥order只能从1而不是0开始?

在 JDBC 中,为啥准备好的语句的参数索引从 1 而不是 0 开始?

数组下标为什么是从0开始的,而不是1?

为啥 MySQL 从 1 计数而不是 0?