我对快速的误导性文档有误吗?

时间:2019-04-14 19:59:06

标签: swift

对于Array方法:

@inlinable public func index(_ i: Int, offsetBy distance: Int, limitedBy limit: Int) -> Int?

文档给出了一个示例:

///     let numbers = [10, 20, 30, 40, 50]
///     if let i = numbers.index(numbers.startIndex,
///                              offsetBy: 4,
///                              limitedBy: numbers.endIndex) {
///         print(numbers[i])
///     }

为什么将numbers.endIndex用于limit参数,这显然是错误的,我们应该使用numbers.endIndex-1,它在这里起作用,因为distance参数为4,它将如果distance为5,则会崩溃。

我认为这是一个不好的例子,还是我错过了什么?

1 个答案:

答案 0 :(得分:2)

您是对的,该代码无法防止出现“索引超出范围”错误。 endIndex是数组(或通常是集合的)“过去”位置:它是有效索引,但下标无效。

对于非负偏移量,

if let i = numbers.index(numbers.startIndex,
                         offsetBy: offset,
                         limitedBy: numbers.endIndex), i != numbers.endIndex {
    print(numbers[i])
}

将是一个安全的变体。对于数组,您还可以使用numbers.endIndex-1作为限制。但是,这不适用于任意集合,因为并非所有集合都由整数索引(String是一个很好的例子。)

您还可以检查是否offset < numbers.count,但是请注意,访问任意集合的count可以是O(N)操作。

另一个变种是

if let num = numbers.dropFirst(offset).first {
    print(num)
}

适用于任意集合。与前面的示例一样,必须分别排除可能的偏移量。

您也可以使用

if numbers.indices.contains(index) {
    print(numbers[index])
}

为了安全起见。如果您记住集合索引不一定是从零开始的,并且不一定是整数,那么这对任意集合都有效。