无法在 Swift 的集合扩展中使用 indices.contains() 3

Unable to use indices.contains() in a Collection extension in Swift 3

我在 Swift 2.3 中写了以下扩展:

extension CollectionType {
    /// Returns the element at the specified index iff it is within bounds, otherwise nil.
    subscript (safe index: Index) -> Generator.Element? {
        return indices.contains(index) ? self[index] : nil
    }
}

然而,原来Swift3.0没有contains()功能。相反,它为我提供了此方法的以下语法:

indices.contains(where: { (<#Self.Indices.Iterator.Element#>) -> Bool in
    <# code ??? what should it do??? #>
})

问题是我不知道块中应该包含什么。请帮助迁移它?

Swift 4 次更新

在Swift 4中,由于the ability to have where clauses on associated types, Collection now enforces that IndicesElement类型与CollectionIndex类型相同。

因此这意味着我们可以说:

extension Collection {

    /// Returns the element at the specified index iff it is within bounds, otherwise nil.
    subscript (safe index: Index) -> Element? {
        return indices.contains(index) ? self[index] : nil
    }
}

Swift 3

Swift3中的Sequence协议还有一个contains(_:)方法,如果序列是Equatable个元素,它接受序列的一个元素:

extension Sequence where Iterator.Element : Equatable {
    // ...
    public func contains(_ element: Self.Iterator.Element) -> Bool
    // ...
}

您遇到的问题是由于 Collectionindices 属性 要求的类型发生了变化。在 Swift 2 中,它是 Range<Self.Index> 类型——但是在 Swift 3 中,它是 Indices 类型(Collection 协议的关联类型):

/// A type that can represent the indices that are valid for subscripting the
/// collection, in ascending order.
associatedtype Indices : IndexableBase, Sequence = DefaultIndices<Self>

因为目前 Swift 中 Collection 协议 本身 无法表达 IndicesIterator.ElementIndex (this will however be possible in a future version of Swift 类型),编译器无法知道您可以将 Index 类型的内容传递给 contains(_:)。这是因为当前类型完全有可能符合 Collection 并使用 所需的任何 元素类型实现 Indices

因此,解决方案是简单地限制您的扩展以确保 Indices 具有 Index 类型的元素,从而允许您通过 index 变成 contains(_:):

extension Collection where Indices.Iterator.Element == Index {

    /// Returns the element at the specified index iff it is within bounds, otherwise nil.
    subscript (safe index: Index) -> Iterator.Element? {
        return indices.contains(index) ? self[index] : nil
    }
}