我不明白Lua这部分决定背后的理由。为什么索引从 1 开始?我已经读过(和其他许多人一样)这篇很棒的论文。在我看来,这是一种学习和编程非常愉快的语言的一个奇怪角落。不要误会我的意思,Lua 很棒,但必须在某个地方做出解释。我发现的大部分内容(在网上)只是说索引从 1 开始。句号。
阅读它的设计师对这个主题的看法会很有趣。
请注意,我是 Lua 的“非常”初学者,我希望我不会遗漏一些关于表格的明显内容。
Lua 是 Sol 的后裔,Sol 是一种为石油工程师设计的语言,没有接受过计算机编程方面的正规培训。没有受过计算机培训的人认为从零开始计数是非常奇怪的。通过采用基于 1 的数组和字符串索引,Lua 设计者避免了混淆他们的第一批客户和赞助商的期望。
虽然一开始我也觉得它们很奇怪,但我已经学会了喜欢从 0 开始的数组。但是我对 Lua 的基于 1 的数组感到满意,尤其是通过使用 Lua 的通用for
循环和ipairs
运算符——我通常可以避免担心数组是如何被索引的。
在Programming in Lua对表的第一次讨论中,他们提到:
由于您可以使用任何值对表进行索引,因此您可以使用任何您喜欢的数字来开始数组的索引。然而,在 Lua 中习惯以 1 开始数组(而不是像在 C 中那样以 0 开始),并且一些工具坚持这个约定。
稍后,在有关数据结构的章节中,他们又说了几乎相同的话:Lua 的内置设施假定索引是从 1 开始的。
无论如何,使用基于 1 的索引有几个方便之处。即#
(长度)运算符:t[#t]
访问表的最后一个(数字)索引,并t[#t+1]
访问超过最后一个索引的1。对于尚未接触过基于 0 的索引的人来说,#t+1
越过列表末尾会更直观。还有 Lua 的for i = 1,#t
构造,我认为它与前一点属于同一类别,即“1 到长度”比索引“0 到长度减 1”更明智。
但是,如果你不能打破基于 0 的索引的思维方式,那么 Lua 的基于 1 的索引肯定会成为更大的障碍。最终,作者想要一些对他们有用的东西;我承认我不知道他们最初的目标是什么,但从那以后它可能已经改变了。
我的理解是,之所以这样,只是因为作者认为这是一种很好的方式,而在他们将语言发布给公众之后,这个决定就变得相当僵化了。(我怀疑如果他们今天改变它,将会付出惨痛的代价!)除此之外,我从未见过任何特别的理由。
也许一个不太重要的点,但我还没有听说过:一个字符串中的第一个和最后一个字符分别位于 1 和 -1,而不是 0 和 -1,因此具有更好的对称性。
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
C 和 Lua 中数组索引的具体定义是不同的。
在 C 数组中,它的意思是:数组地址的项地址偏移量。
在 Lua 数组中,它的意思是:数组中的第 n 项。
为什么大多数语言使用从 0 开始的索引?因为编译代码用起来offset definition
更方便有效。他们主要处理地址。
和 Lua。这是使用 C 的表索引的 lua 5.3.5 代码:
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;
}
}
我们应该关注代码&t->array[key - 1]
,它有一个减法运算。与从 0 开始的索引相比,它是无效的。
但是,基于 1 的索引更接近人类语言。我们更关注英语、汉语、日语等的第 n 个项目。
所以,我猜Lua的设计者选择了基于1的索引,他们选择了易于理解的纯粹更新程序,放弃了便利性和有效性。
真正的原因是该语言是葡萄牙法律中定义的实现,而主要的发展中心在巴西,他们的偏好是避免使用零或空或无作为索引或下标。但是,在某些版本中,该语言确实允许在表创建函数中使用 1 以外的起始索引。
在您的示例中,table[0]
将始终return nil(null)
,除非您自己为其分配值,例如table[0] = 'some value'
然后table[0]
将 return'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]))
对每个人来说都是有意义的,如果
table = {}
table
是空的。那么,当
table == {something}
该表包含一些东西,所以它包含的是索引 1 in table
,如果你知道我的意思的话。
我的意思是table[0]
存在,table = {}
它是空的,现在程序员不会调用空表,它设置它们,然后填充它,每次要调用它都找不到空表是没有用的,所以只创建一个空表更简单。
我的英语不会变得更好,这是我最好的语法。如果您不喜欢它,您可以不继续阅读它,但是为试图帮助的人提供 -rep 会使人们根本不想提供帮助,尤其是对于语法之类的东西。我是一个数字和变量,而不是语法的人。对不起。