Swift中数组的endIndex的正确行为是什么?

fkvaft9z  于 2023-03-11  发布在  Swift
关注(0)|答案(3)|浏览(176)

endIndex返回与count相同的值。这是一个正确的行为还是一个错误?

var ar = [1, 2, 3, 4]
ar.count // 4
ar.endIndex // 4
7hiiyaii

7hiiyaii1#

count是集合中的项数,而endIndex是刚过集合末尾的Index (from the Collection protocol)
对于Array,它们是相同的。对于其他一些集合,如ArraySlice,它们不是:

let array = ["a", "b", "c", "d", "e"]

array.startIndex  // 0
array.count       // 5
array.endIndex    // 5

let slice = array[1..<4]  // elements are "b", "c", "d"

slice.startIndex  // 1
slice.count       // 3
slice.endIndex    // 4
olmpazwi

olmpazwi2#

Array.endIndex是指数组末尾后的1(或与count相同),用于迭代目的,而不是下标。

let x = [1, 2, 3, 4]
for var i = x.startIndex; i < x.endIndex; i++ {
    println(x[i])
}
bqjvbblv

bqjvbblv3#

这里似乎有很多评论说endIndexstart之后的count元素是违反直觉的。我不能说对一个人或另一个人来说什么是直觉的,但这不是随机的。这是一个非常明智的工作方式。
我相信有些人会想到这样的索引,索引直接指向包含值的“框”:

|-----|-----|-----|-----|
|  0  |  1  |  2  |  3  |
|-----|-----|-----|-----|
   ↑                 ↑
 start              end

但这并不是正确的思考方式,正确的方式是这样的,索引指向你开始阅读值的边界:

|-----|-----|-----|-----|
|  0  |  1  |  2  |  3  |
|-----|-----|-----|-----|
↑                       ↑
start                 end

如果一个人从起点开始,向前推进count倍,他应该期望到达终点,这就是它所达到的目的。
现在考虑空列表的情况:

|
|
↑
start
↑
end

所有的事情都和预期的一样。如果你从start开始,并前进0个元素,你会到达end。我在这里故意说“前进”。索引不一定是整数。它们只需要有一个“前进”操作和一个结束。
如果endIndex是“最后一个元素的索引”,那么对于一个空列表,它是什么呢?没有最后一个元素。当索引是有符号整数时,将它设置为-1是一种可能的回避,但是Swift根本不要求Collection索引是整数(事实上,它们通常不是;数组是非常不寻常的)。Swift可以使endIndex可选,但这使数学更加丑陋。
正如HangarRash在评论中指出的,对于Int索引不从零开始的集合(特别是ArraySlice和切片Data),endIndex在任何情况下都不会是count - 1,对于空切片,即使偏移startIndex + count - 1也不会是-1(所以你不能只检查-1来表示“空”),并且可以指向包含它的Array,这显然是错误的。规则endIndex = startIndex + count和“空集合具有startIndex == endIndex”对于切片仍然同样地起作用。这种方法在各种情况下是一致的,而不需要变通方法。
从起点到终点的距离应该是计数(而不是比count少一),long早于Swift,并且与许多语言从零开始而不是从1开始对数组进行编号的原因密切相关。(“上述边界之间的差异等于子序列的长度”)看起来违反直觉(有时候我确实觉得很惊讶!),这种方法非常强大。它不是关于性能或“C使用指针”或类似的东西。而是因为它使算法更漂亮。

相关问题