从一开始计数

lua-users home
wiki

与今天大多数流行的语言不同,Lua 的数组索引代表数组中的一个顺序位置,而不是从数组开头开始的偏移量。(这种方案不幸地被称为“从一开始计数”,导致许多人将其辩护为自然的计数方式。实际上,争论在于使用偏移量还是顺序位置来指示序列中的元素。)

在 Lua 核心中,只有一种情况是这样的:解析构造函数,例如 {10,20,30} 。从 1 开始的约定仅由库强制执行,而库不是语言的一部分。--lhf

Lua 5.1 不再是这样了,因为 # 运算符也依赖于 1 的基数索引。


你误解了长度运算符。引用 Nick Gammon 在下面几段中的话

来自 Lua 手册

表 t 的长度被定义为任何整数索引 n,使得 t[n] 不为 nil 且 t[n+1] 为 nil;

这个定义(来自 Lua 5.1 手册)暗示表 { [-3] = 0 } 的长度为 -3,而完全空的表 {} 没有长度(而不是长度 0)。这比从零开始计数更违反直觉。出于某种原因,PUC-Lua 5.1 不遵守此定义:#{ [-3] == 0 } == 0。(Lua 5.2 手册将定义更改为明确从 1 开始计数。对于空表来说,这仍然相当模糊,除非你知道 n 小于 1 时的范围 {1..n} 是什么——并且在不落入类似陷阱的情况下定义它有点棘手。)--f.

好吧,我们来解决这个问题:定义一个代理表指向真实表,通过重写索引元方法,当 i 为正数时,则访问真实表的 i-1。决定何时将负数索引直接映射到真实表,或者是否进一步处理它们。决定如何处理真实表的索引 0。

完成之后,当你需要从零开始计数时,就使用代理表。当你需要使用库函数时,就使用真实表。为了方便记忆,将你的表命名为 'tablename1',代理表命名为 'tablename0'。问题解决了。


如果你被称作“脚本编写者”或“非程序员”,那么是时候为未来的语言发声了。让大家知道,你完全有能力像任何程序员一样理解偏移量的概念。Lua 列表的基础索引是 1,因为它被认为对非程序员最友好,因为它使索引对应于顺序元素位置。然而,这种可疑的让步给程序员带来了很多痛苦,这反过来又降低了他们为你提供工具的效率。一个原因是 Lua 与 C 紧密耦合,而 C 使用 0 作为数组的基本索引——索引代表从数组开头开始的偏移量。这意味着同时处理 Lua 和 C 的程序员必须不断地在他们的代码和思维中切换参照,这既烦人又容易出错。此外,事实证明,使用偏移量与一种特定的指定范围的方式相吻合,即结束时不包含(称为半开区间),而使用顺序位置则不然。半开区间可以更自然地处理零长度区间,从而实现更简洁一致的程序。

我同时是 C++ 和 Lua 程序员,我完全不同意这篇抱怨。从 1 开始计数是“自然”的计数方式。在数学中,每个人也从 1 开始计数。从 0 开始计数只对 C 约定有利,即数组和指针是等价的,并且 a[i] 与 *(a+i) 相同。另外,我认为程序员很容易适应非 C 风格的计数方式。然而,这使得 Lua 对“休闲程序员”更直观。--PeterPrade

同意,这是一篇抱怨 :-) 。然而,你的论点并没有解决半开区间如何实现更简洁编码的问题,这是我的主要观点。当处理 Lua 中的范围时,程序会倾向于充斥着 +1,因为 Lua 不使用半开区间,而在 C++ 中(尤其是在使用 STL 时,STL 完全使用了这种范围风格)就不会发生这种情况。此外,我同意从 1 开始计数对人类来说是自然的(我从未说过相反的话),但是用 [n, n-1] 来表示零长度区间非常尴尬。通过指示某人地板上的起点,然后指示一个在其后一步的目的地来传达“向前迈出零步”是不自然的。相反,人类可以很容易地通过指示地板上的起点和相同的点作为目的地来理解“向前迈出零步”——这对应于半开区间 [n, n)。--JohnBelmonte

集合论者、逻辑学家和组合数学家从零开始计数。Z/nZ(模 n 的整数)环的元素通常命名为 {0, 1, ..., n-1},因此代数家也从零开始计数。这些都是与 CS 密切相关的学科,因此也与编程相关。在分析学中,人们经常从 1 开始计数,但这并不真正相关——自然数集通常在那里用于其拓扑,或者仅仅作为一个方便的索引集,具有明确定义的“向后移动”和“向前移动”操作(即使在这种情况下,包含零的定义也更优雅),使得选择起始点有些任意(也可以是 42)。选择 1 通常是出于习惯、避免破坏“向后兼容性”(即与使用一进制编号的材料相互理解)或避免在分母/指数/其他地方考虑零。--f

有时半开区间可以实现简洁编码,有时则不能。我见过(并提交过)大量半开和闭合区间都有的“围栏柱”错误。例如,C 数组中最后一个元素的索引比数组长度小一,这可能导致代码中出现各种 -1;可以肯定的是,有消除这些的方法,但我不会说我的 Lua 代码中的 +1 比我的 C 代码中的 -1 多。然而,对于半开区间,存在一个严重的问题:你需要能够表示不在范围内的数量。因此,例如,长度为 256 的字符串的索引类型至少需要是 short,即使每个有效索引都是一个字节。类似地,指向向量末尾的半开区间描述符包含一个不包含在向量存储中的地址,并且可能是一个指向另一个对象的有效指针;例如,这对保守垃圾回收来说很复杂。(至少有一个保守垃圾回收器会故意过度分配以弥补这个问题。)我不是支持这个或那个:两者都是有效的,都有优点,也有缺点。--RiciLake

你的论点不成立,RiciLake。你有一个包含 256 个字节的数组,并且使用“闭合”表示法,其中 (n, m) 表示 [n, n+1, n+2 ... m-1, m],来表示该数组中的区间。如上所述,零长度区间的表示是 (n, n-1);例如,[4, 3]。那么零长度区间从零开始的表示是什么?(0, 256) 还有另一个含义。因此,你关于数组索引需要多少位的论点,对于半开和闭合区间表示法来说同样是一个问题。对于像 Lua 这样不能选择使用多少位来表示的语言来说,这是不相关的。--KragenJavierSitaker?

与从一开始计数一样,我认为闭合区间比半开区间更直观,至少当你谈论零长度区间的特殊情况时。当我使用“直观”时,我的意思是对于一个至少几年没有做过程序员的人来说,它更自然。--PeterPrade

我没有数过,但我想大量的编程语言从零开始计数……而且,当我把 C 作为我的第一门语言来学习时,从一开始计数似乎令人困惑——事实上,我写了一堆糟糕的 Lua 代码,想着从零开始计数——AdrianPerez

虽然从零开始计数有其优点,但我发现从一开始计数更为自然,即使在编程时也是如此。我切换 Lua 和 C 之间没有问题,因为过去我经常在 Visual Basic 和 C 之间切换——匿名

第一个是第一,不是第零 --Kazimir Majorinc

“我正在为一个嵌入式脚本语言评估 Lua,在我看到的到目前为止的一切都非常积极,直到我意识到 Lua 是从索引 1 开始计数的。坏。坏。非常坏。糟糕到足以考虑将整个东西丢掉。至于理由,虽然不应该需要任何理由:长度为 N 的数组的索引自然地映射到模 N 的整数环,它有很多巧妙的性质。例如,当你想要循环访问数组时,你只需要做 index = (index+1) %N。用从 1 开始的索引做同样的事情是件很麻烦的事。此外,它使得将 C 例程绑定到 Lua 变得非常痛苦。”

index = index % N + 1 --Milano Carvalho

没错,突然我们就出现了一个错误和额外的麻烦,而这些本来是不必要的。此外,程序员现在必须记住“索引是一个位置并且违反了模数前提条件,还是它就是实际的模数?”最后,它的逆运算是什么?是“modindex = index - 1 % N”还是“modindex = index % N - 1”?棘手的问题:它是“modindex = (index - 1) % N”。 --Andrew Lentvorski

同意。Lua C 库接口对 C 使用的约定对 C 来说是不自然的。例如,当解析 Lua 表到 C 数组时,你必须记住使用 iterator+1 来访问表索引。--DanHollis?


对我个人而言,从零开始计数不是棘手的问题;从一开始计数只是 Lua 数据类型稀缺问题的一个症状,远非问题的全部。我的问题是,数据类型的缺乏,包括那些数组,无论是以 1 还是 0 为基础,都无关紧要。表可能有紧密打包的“数组”部分,但我不太喜欢我 33 个字的数组占用 64 个字的存储空间(必须是 2 的幂)。更不用说我甚至不能拥有一个字节数组,而只能使用巨大的双精度浮点数(或双精度浮点数,或者 Lua 编译时使用的恰好一个(1)数值类型)。是的,我知道 Lua 可以轻松地与 C 中的真实数组连接。但那样它就不是真正的 Lua 了,它是一种我无法真正当作普通列表对待的二等“userdata”类型。

Lua 5.1 提供了 lua_createtable() API 调用,允许你精确地指定表的数组大小。你也可以指定哈希大小,但这部分始终限制为 2 的幂。如果你创建一个指定了数组大小的表,那么只要你不强制表扩展,它的数组部分就是该精确大小,所以如果你提前知道表的大小,它就会正常工作。在 5.1 中,绑定小原子对象的数组,如 ints,也变得更容易一些,因为可以覆盖 # 运算符,但要使 userdata 真正像 Lua 表一样工作,你需要修改 ipairs 和可能的 unpack 的默认定义。我在 Wiki 上为前者放了一些代码,网址是 GeneralizedPairsAndIpairs,以防它对任何人有用。--RiciLake

一个绝妙的观点,这也是我一直挣扎的问题。将大型 C 结构体接口到 Lua,尤其是大型结构体的 C 数组,并不是一件有趣的事。Lua 并不能让这些映射变得简单明了。--DanHollis?


Lua 源代码中有一个常量 lua_Number,默认设置为 double。同样,定义一个常量 lua_FirstIndex(例如)设置为 1 作为默认值,以引用第一个索引,可能会很有趣。Lua 中与数组第一个索引相关的所有部分(例如,ipairforeachi 等)都应该使用此常量。如果用户想将此常量更改为 0 并重新编译,他/她可以从 0 开始使用 Lua 表,但需要自行承担丢失兼容性的风险。相同的常量也应该可以从 Lua 访问,以便脚本能够移植或独立于数组索引值的第一个值。--Salvador Espana


计算机科学中计数是否应该为零基或一基是一个经典问题。我认为 Edsger Dijkstra 的文章“Why numbering should start at zero”(http://www.cs.utexas.edu/users/EWD/ewd08xx/EWD831.PDF)中的论点非常有说服力,我成了一个坚定的零基计数拥护者。太糟糕了,Lua 建议从 1 开始。这会使表/数组的构造变得尴尬: {[0]=10, 20, 30} 以及库函数的作用就打了折扣。--Ulrich Hoffmann <uho@xlerb.de>

是的,一篇好文章。我尤其喜欢第一句话:“为了表示自然数 2, 3, ..., 12 的子序列 [...]。”现在,将其与计算机语言应主要向读者传达其意图,而仅仅偶然向计算机传达这一度量结合起来,我们就会发现,即使对 Dijkstra 来说,最自然的表示法也是包含性的......自己得出结论。


从一开始计数“更直观”,但从零开始计数“算法上好得多”。这是一个用于编写要由计算机执行的算法的编程语言,而不是用于人与人之间日常对话的语言。程序员很聪明,他们能弄明白。不要像对待孩子一样对待他们。:) --DanHollis?


我赞成使用半开区间而不是闭合区间,因此赞成从 0 开始计数而不是从 1 开始计数。零长度区间不仅可以自然地表示为 [n,n),而且相邻区间可以很好地加起来——[a,b)+[b,c)=[a,c)——而不会在端点处过度重复。结果区间是 (b-a)+(c-b)=c-a 长,并且任何或两个分量都可以是零长度。此外,还可以考虑“负数区间” [m,n),其中 m>n,并且区间的加法仍然有效,现在甚至可能从非零区间获得零长度区间。

现在,考虑数字 abx。在 min(a,b)<=x<max(a,b)(半开区间)的意义下,“xab 之间”的正确表达式是 (a<=x)=(x<b)。如果是闭合区间(...<=x<=...),我们就没有这么好的表达式了。-- Boyko Bantchev


就我个人而言,我并不介意从一开始计数。一方面,1 是字符串中第一个字符,-1 是最后一个字符的习惯是一个好主意。如果第一个字符是 0,那将不起作用。

作为一个脚本语言,它的首要任务是易于脚本编写者使用。一个有 5 个元素的数组,最后一个元素是数字 5,肯定比说它以元素 4 结束更容易向休闲脚本编写者解释?

我已经将许多客户端函数接口到我的系统中,以向 Lua 公开它们的工作方式。在许多情况下,零基或一基的问题甚至不适用。例如,许多使用字符串键(在这种情况下问题消失),或者它们不使用任何类型的数组。

如果你希望 Lua 成为一种通用的脚本语言,我绝对不推荐编译时选项,这样一半发布的 Lua 脚本将基于零,一半基于一。这样做你会打开一个噩梦的大门。如果你想接口像 LuaSocketLuaCom 等,我甚至看不到它如何工作。这些将假定当前的约定,即数组从 1 开始,许多都附带预编译的 Windows 二进制文件。在零基系统上运行它们时,它们要么根本不起作用,要么每个包的作者都必须用测试来充斥他们的代码,以确定基数是什么,这肯定会失去改变它的任何好处。-- NickGammon


再一点,Lua 内部在许多地方都使用 1 作为第一个,-1 作为最后一个的约定。例如

double num = luaL_checknumber (L, 1); /* get first item on stack */

因此,将 Lua 与 C 接口的程序员非常熟悉该约定——你必须熟悉。同样,如果你将数组设为零基,你会改变这一点吗?那样的话,你如何从堆栈中获取最后一个元素(当前是 -1)?

上面的一些帖子并没有真正提到它们是否也提到了字符串。例如,字符串中的第一个项

c = string.sub ("ABC", 1) --> "A"

你会把那个也设为零吗?如果是,你如何获取最后一项?-- NickGammon

将 -1 用作最后一个元素的别名与半开区间(即从零开始计数)是完全一致的。参见 Python。事实上,它比闭合区间更一致。暂时考虑一下,列表会环绕,你可以从开头到结尾,再“短路”回来。“0”(列表开头)左边是 -1(列表结尾)。换句话说,你只需从你的位置减去 1 就可以向左移动,这是自然的。如果你从 1 开始列表,它会在开头和结尾之间产生一个奇怪的两个位置的间隙。要向左移动,你需要从你的位置减去一,除非你在位置 1,在这种情况下,你需要减去二。

那么你还建议 greatest_index + 1 是否会环绕到第一个元素?如果不是,那么在从最后一个元素(用正索引指定)到第一个元素的跳转时仍然会有这些“奇怪的”跳跃,所以这个论点毫无意义。

不——如果你想让索引环绕,就使用 i 模 n。那个方程的简单性是索引偏移量的一个吸引点。

是的,这是真的。然而,鉴于“事已成定局”现在,我建议那些出于数学或其他原因需要“从零开始计数”方法的应用程序,只需定义自己的 foreachi 函数来解决当前行为。毕竟,现在没有任何东西阻止你把元素放入表的第 0 位。

如果你想让表构造函数从 0 开始,这样做

t = { [0] = "a", "b", "c" }  -- a is in position 0, b is in 1 and so on

-- NickGammon

不幸的是 #t 的结果是 2。很多问题源于数字和序数之间的混淆。当索引是偏移量时,0 是数组中第一个项的偏移量。如果我们更严谨地在日常口语中使用数字时保留类型信息,那么争论就会少一些。在数学中,将一个非负整数 n 实现为从 0 到 n-1 的数字集比将其标识为从 1 到 n 的数字集能给出更简洁的公式。-- GavinWraith

虽然在数学中,矩阵和向量通常是一基索引[1][2][3]。类似地,在LuaMatrix 中,第一个元素被引用为 mtx[1][1]。序列可能更具可变性[4]。关于数学软件,Mathcad 默认使用 0 索引(尽管可以更改),而 Matlab、Maple 和 Mathematica 使用 1 索引。--DavidManura


然而,#t(或 table.getn)并未定义为返回表中的元素数量。例如

t = { foo = 1, bar = 2 } ; print (table.getn (t))  --> 0

来自 Lua 手册

表 t 的长度被定义为任何整数索引 n,使得 t[n] 不为 nil 且 t[n+1] 为 nil;

我的例子与定义一致。#t 返回最后一个项目的索引。

-- NickGammon

并非如此。t[0] 为 nil。根据该定义,此表根本没有明确定义的长度。见上文。--f


Visual Basic,尤其是 JavaScript? 是两种与 Lua 相似的语言。对于从这些语言迁移过来的非技术用户来说,能够拥有一个低入门门槛会很好。在 JavaScript? 中,数组从 0 开始索引。在 Visual Basic 中,数组默认从 0 开始索引。(强烈不建议更改默认设置,并且现代实现(如 VB.Net)不支持。)


我一直在看 Perl 是从 0 还是 1 开始索引(似乎是零),并在我的 Perl 手册中找到了这个珍宝

数组下标 n,其中 n 为任何非负整数,始终指向数组元素 n+1。

很明显我们在这里无法达成一致,但你不认为这“稍微”有点令人困惑吗?“下标 n ... 指向元素 n+1?”至少在 Lua 中,下标 n 指向元素 n。

-- NickGammon

只有当你的基数是 0 并且你将索引视为位置时,它才会令人困惑。如果你的基数是 0,那么最好将索引视为列表开头的偏移量,而不是位置。这与 Gavin 刚才提出的观点相同。总的来说,偏移量在编程中比位置更有用。


“自然数集”在美国是指大于或等于零的整数集,而在苏联是指大于零的整数集。这就像缩进一样。

在我看来,从一开始计数很棒。第一个元素是 1,最后一个元素是 -1。无需记住“这不是数学,这不是自然的事,适应它”,就像你在 Python 中处理索引时一样。

-- muntyan

而且 Lua 允许你在整数中存储 0——那么它会带你到哪个元素?


Lua 的关键优势在于它是脚本语言中最易于嵌入的——它并不是进行通用编程任务的最佳顶级脚本语言(Python 和 Perl 更好)。作为一种嵌入式脚本语言,它将被嵌入到编译型语言中。几乎所有这些都使用零基索引,所以大多数新用户将拥有这个参照系。VB 曾经有过这个争论(以及选择动态选项),从我看到的情况来看,人们投票支持零基索引。所以我们干脆这样做,把这件事了结吧。-- GRB

完 全 正 确 -- JeanClaudeWippler


请不要在不署名的情况下用第一人称写作。

那么所有这些数论都白费了吗?天哪,你出生时就一岁了,克拉克先生在 2001 年就错了。模 -0 有多大帮助。对不起,但我想整个想法都需要重新思考、修改和纠正。不,从一开始计数不像一个人写的那样自然,这是因为零是直观地假设的;因此;不需要说明。但老实的电脑不会假设。只是我的想法 ---trav
在 BASIC 中,你可以从任何你想要的数字开始,比如
 DIM arrayname(5 to 18)
在 Forth 中,你也可以从任何你想要的数字开始,比如
 HERE 14 ALLOT 5 - CONSTANT arrayname

非程序员实际上已经在意识到它的同时从 0 开始计数。计数时,人们用什么作为十、百、千等的第一个数字?提示:不是 1。所以使用 1 作为第一个单位是非常不一致的。这种不一致性也解释了为什么许多人认为 21 世纪始于 2000 年。通过假设这一点,他们只是更方便地从...零开始计数。另一个例子:一天/下午的第一个小时用哪个数字?提示:再次,不是 1。与从一开始计数相关的另一个不一致性:我们使用十个数字,现在请说出最后一个数字?有关更多非书呆子、非数学的例子,请参阅 Stefan Ram 的文章“Numbering Starts with Zero”。

看来从一开始计数是从一元系统遗留下来的非常古老的传统。我们在发明零时本应摆脱它,但可惜没有。


从一开始计数是我不使用 Lua 的头号原因。除此之外,它是一种非常好的语言,但使用半开区间编码要容易得多。我不同意人们告诉我“从一开始计数更自然”。这只是过去遗留下来的东西。如果你真的仔细考虑,从零开始计数更有意义。

--Zifre


Zifre,你不是想说“从一开始计数是我不使用 Lua 的*零*个原因吗?”?毕竟,你声称从零开始计数对你来说更有意义。

我们来打个赌。我们去公园找随机的人。我们会给他们看一排三块石头,让他们大声数出来。如果有人说,“零,一,二”,你就赢了。如果每个人都说,“一,二,三”,我就赢了。我猜我总是会赢得这个赌局。没有人从零开始计数,因为它没有意义。当数组的第一个元素用 0 访问时,那个数字代表一个偏移量,而不是索引。问题不在于计数,而在于数组是否应该使用偏移量或索引。

使用偏移量而不是索引当然也有一些优点。但很难反驳这一点:如果数组使用索引,那么“第 n 个”元素就用数字“n”来访问。你想要第四个元素吗?那么用 4。想要第十个?那么用 10。这很有意义,并且有自己的一套很好的性质。不幸的是,许多程序员在这个问题上思想封闭,并且不知何故说服自己相信荒谬的陈述,例如“从 0 开始计数更有意义。”(然后,在他们自己的帖子里,说明他们实际上就像这个星球上的其他人一样,是从一开始计数的。)

我们来打第二个赌。在让人们数石头之后,我们会说:“请指向石头一”。如果有人指向中间的石头,你就赢了。否则,我赢。同样,我看不出我如何会真正输掉这个赌局。-- 匿名

Zifre 对阵匿名对这个页面的讨论没有任何贡献。你读了第一段吗?问题不在于从一或零开始计数,而在于如何指示序列中的一个元素。使用偏移量会导致更少的边缘情况,因此代码和 API 更简单。这与公园里的人如何计数无关。--JohnBelmonte

考虑到 Lua 的主要用途之一是业余脚本编写,例如在允许非熟练程序员但仍然提供定制功能的地方,“公园里的人”如何计数相当重要。并非所有东西都应该为了全能的消费者而变得过于简单,尤其是程序员应该用来开展业务的工具,但由于偏移量与基数的争论在很大程度上是一个概念性问题,涉及到你如何内化你的代码的含义,为什么还要责怪 Lua 迎合公园里的人,那里的第一块石头是石头 1?对于那些不熟悉偏移量的人来说,偏移量是一个进入的障碍。

好吧,让一台计算机来数这 3 块石头。你会得到类似这样的结果:00、01、10。你在这里忽略了重点:你不是在编程人,而是在编程计算机。了解计算机的内部工作原理通常会有帮助。你永远无法让计算机完全理解你(或者也许可以,但那样的话你应该获得诺贝尔奖)。然而,你可以完全理解一台计算机 :) -- shiretu


我将就这个话题开一个新页面,试图总结问题的几个方面:[IndexIntervalFormatIssue]。[DeniSpir]
DeniSpir,那个页面有一个巨大的误解。“程序员也”部分,半开区间被描述为 [n,n],而它们应该是 [n,n)。

另外,[a,b]+[b,c] 应该变成 [a,b]+[b+1,c] 的说法完全是错误的,因为原始命题需要半开区间,在这种情况下,它看起来是这样的:[a,b)+[b,c)。

因此,这个抱怨完全是错误的,因为 [a,b)+[b,c) 不会重复包含 b。我将纠正那部分,并删除关于 [a,b]+[b+1,c] 的抱怨,因为它没有意义。-- Tim


JohnBelmonte,使用偏移量并不会使代码 API 更简单。同意,边缘情况更少,但不要试图说服人们喜欢/不喜欢某种特定的编程模式。这里重要的是 Lua 应该支持多样性。我自己就很难设计出 1 开头的代码,而且比你所谓的“边缘情况”更容易出错。换句话说,我本能地知道如何利用我从其他 10001 种编程语言中学到的技能来避免边缘情况,而不是采用你“安全”的“更简单的代码”开发方法。真的,这只是品味问题。你不能将人们归类为“你因为这样编程而愚蠢,你因为那样编程而聪明”。尽管 Lua 有这个我讨厌的地方,但它仍然得到了我的很多喜爱,因为它还有很多其他的优点。但我确实想念一点……能够在编译时指定索引基数。-- shiretu
这是错误的。原因如下:Edsger Dijkstra 关于从 0 开始数组索引的说明(pdf,1982 年)[5]。-- Anonymous


我对 Lua 5.3.4 源代码发行版进行了补丁尝试,包括所有官方库:lua-base-0。已开源[6]。如果你感兴趣,请去查看(并移植到最新的 lua,为最好的写一些测试用例),看看我是否遗漏了什么。

一些例外

string.gmatch 中,"%0" 表示整个匹配,"%1%2"... 表示第一个、第二个捕获。未改变。

args 表的订阅定义未改变,但请注意,长度运算符现在将返回一个比实际长度大 1 的数字。

math.random 是一个不确定的点。当前状态主要是为了实用性:当提供 1 个参数时返回 [0, n),当提供 2 个参数时返回 [a, b]。

数值 for 循环是另一个。当前状态是:for i=0,3 返回 {0,1,2},for i=3,0,-1 返回 {3,2,1}。

我正在考虑也将后者设置为 {2,1,0},因为它只是作为反向迭代。但这在定义上看起来会很丑陋,而且可能会出现一些浮点数问题。(但说实话,我好奇,谁在生产环境中用过它?)你觉得呢?

table.remove 的边界情况,其中 i==#t+1 (i==#t base-0) 已被移除。我不理解它。现在它会引发一个错误。

其余部分应该是微不足道的,包括一些支持负数索引作为反向索引的情况,它们在很大程度上会像 Python 一样工作。

我反对 base-1 表的另一个原因是:它在转换 JSON(一种广泛使用的数据交换格式)时会引起问题和混淆。

--farter

另请参阅


RecentChanges · preferences
编辑 · 历史
最后编辑于 2018 年 3 月 18 日晚上 9:54 GMT (diff)