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

Viv*_*ive 10 swift swift3 swift2.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
    }
}
Run Code Online (Sandbox Code Playgroud)

但事实证明,Swift 3.0没有contains()功能.相反,它为我提供了以下语法:

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

问题是我不知道它在块内应该包含什么.请帮忙迁移它吗?

Ham*_*ish 27

Swift 4更新

在夫特4,由于能力具有where对相关联的类型的条款,Collection现在强制执行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
    }
}
Run Code Online (Sandbox Code Playgroud)

斯威夫特3

SequenceSwift 3中的协议仍然有一个contains(_:)方法,如果序列是Equatable元素,它接受序列的一个元素:

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

您遇到的问题是由于类型的变化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>
Run Code Online (Sandbox Code Playgroud)

由于有目前在斯威夫特没有办法的Collection协议本身来表达IndicesIterator.Element是类型的Index(然而,这将有可能在斯威夫特的未来版本),有没有办法让编译器知道你可以通过类型的东西Index进入contains(_:).这是因为目前完全有可能的类型,以符合Collection并实现Indices任何元素类型就是了.

因此,解决方案是简单地限制你的扩展,以确保Indices 不会有类型的元素Index,让你传递indexcontains(_:):

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
    }
}
Run Code Online (Sandbox Code Playgroud)

  • 这里http://stackoverflow.com/a/30593673/1187415是一个不需要任何约束的解决方案. (3认同)
  • 尽管如此,可能只提供了一个角落案例的提示,但提示:有些情况下,链接的问答中简化的"O(1)""安全"下标版本仍然不完全安全,而"O(n)"上面的版本是:对于`Collection`与`Indices`不连续.例如,对于`Set`实例,_if_我们通过索引(`SetIndex <Element>`)访问一个set元素,我们可以运行到`> = startIndex` end` <endIndex`的索引的运行时异常,在这种情况下安全下标失败(参见例如[这个人为的例子](https://gist.github.com/dfrib/85398f9d3d5bfc9757905b499d79e26f)). (3认同)