为什么C#8数组切片功能中新的hat-operator索引不从0开始?


156

C#8.0引入了一种对数组进行切片的便捷方法-请参见C#8.0官方博客

访问数组最后一个元素的语法是

int value[] = { 10, 11, 12, 13 };

int a = value[^1]; // 13
int b = value[^2]; // 12

我想知道为什么向后访问元素的索引从1开始而不是0?是否有技术原因?


11
请注意,C ++范围也是[beginInclusive, endExclusive)。这是一个常见的约定。
发动

3
@Sinatr:根据该博客文章,返回所有内容的语法为value[0..^0],因为结尾索引是唯一的(多数其他语言也是如此)。另外,方便地value[^i..^0]给您最后的i物品。
BlueRaja-Danny Pflughoeft

1
@bommelding:C ++ rbegin()有点不同意这个概念-超出该范围的第一个项目也不是一个超越目标的项目。;-)
DevSolar

1
哦,很酷,这看起来像是python中的负索引:value[-1] # 13
cs95

1
@coldspeed在Ruby中与Python相同。我猜他们俩都从Perl借用了这个约定。
韦恩·康拉德

Answers:


170

官方回答

为了获得更好的可见性,以下是Mads Torgersen的评论,解释了C#8博客文章中的这一设计决策:

在开始和结束算法方面,我们决定遵循Python。 0 指定第一个元素(一如既往),并  ^0 指定“ length'th”元素,即最后一个元素。这样,您将获得一个简单的关系,其中元素从开始的位置加上其从结束的位置等于长度。 如果您自己进行数学运算,则  x in  ^x是从长度中减去的值。

为什么不使用减号(-)而不是新的帽子(^)运算符?这主要与范围有关。再次与Python和大多数行业保持一致,我们希望我们的范围在开始时就包括所有内容,而在结尾时要包含所有内容。您传递的要说范围应该一直到最后的索引是什么?在C#中,答案很简单:x..^0从头到尾  x 。在Python中,没有可以提供的显式索引:-0不起作用,因为它等于0第一个元素!因此,在Python中,您必须完全不使用end索引来表示到达末尾的范围:x..。如果计算了范围的末尾,那么您需要记住要有特殊的逻辑,以防万一0。正如x..-y,在那里y被计算出来了0。这是常见的麻烦和错误源。

最后,请注意,索引和范围是.NET / C#中的第一类类型。它们的行为不依赖于它们的应用,甚至不用于索引器。您可以完全定义自己的使用Index的索引器,以及定义另一个使用的索引器Range–我们将在eg中添加这样的索引器  Span。但是,例如,您也可以使用采用范围的方法。

我的答案

我认为这与我们习惯的经典语法相匹配:

value[^1] == value[value.Length - 1]

如果使用0,则两种语法并排使用时会造成混淆。这样,它具有较低的认知负荷。

其他语言(例如Python)也使用相同的约定。


13
轻微修正的Mads评论:你必须在蟒蛇完全离开关结束索引。您可以使用None代替数字:[0,1,2,3,4][2:None] == [2,3,4]。但是,是的,您不能使用整数作为结束索引(显然不计算长度)。
Giacomo Alzetta

4
等等..怎么了x..?看起来还不错,我从没遇到过python [3:]语法问题。
mowwwalker

8
@mowwwalker-报价中是否已包含该内容?“所以在Python中...如果计算了范围的末尾,那么您需要记住要有特殊的逻辑以防万一它变成0”
Damien_The_Unbeliever

3
@mowwwalker Mads的评论涉及一些情况,在这种情况下您不知道索引值将是什么,因为它是以某种方式计算的。他们说,如果要计算endIndex为负索引(即末尾的索引),则负数和正数之间将存在不连续性,因为0在这种情况下无法正确工作。正如我指出了必须更换0None了点。这意味着您的代码应看起来像seq[startIndex:endIndex or None]例如。or None如果endIndex预期为正,则应省略。
Giacomo Alzetta

5
很高兴看到他们没有用-0重复Python的错误。处理这种特殊情况非常麻烦,而且也很容易忘记。
user2357112支持Monica19年
By using our site, you acknowledge that you have read and understand our Cookie Policy and Privacy Policy.
Licensed under cc by-sa 3.0 with attribution required.