【问题标题】:Creating a ValidIndexCollection protocol in Swift 3在 Swift 3 中创建 ValidIndexCollection 协议
【发布时间】:2016-12-24 01:30:24
【问题描述】:

不久前,我在 Swift 中创建了一个二叉搜索树类型,我希望它符合 Collection 协议。但是,endIndex 要求是一个“结束”索引,它并不真正适合树,因为每个索引都应该包含对其对应节点的引用以进行 O(1) 访问。我最终得到了一个可选引用(在 endIndex 的情况下为 nil),但它涉及到很多我宁愿避免的样板代码。

我决定创建一个如下所示的ValidIndexCollection 协议:

/// A collection defined by valid indices only, rather than a
/// startIndex and a "past the end" endIndex.
protocol ValidIndexCollection: Collection {

    associatedtype ValidIndex: Comparable

    /// The first valid index if the collection is nonempty,
    /// nil otherwise.
    var firstValidIndex: ValidIndex? { get }

    /// The last valid index if the collection is nonempty,
    /// nil otherwise.
    var lastValidIndex: ValidIndex? { get }

    /// Returns the index right after the given index.
    func validIndex(after index: ValidIndex) -> ValidIndex

    /// Returns the element at the given index.
    func element(at index: ValidIndex) -> Iterator.Element

}

在我可以扩展这个协议以满足Collection 的要求之前,我必须先引入一个合适的索引:

enum ValidIndexCollectionIndex<ValidIndex: Comparable> {
    case index(ValidIndex)
    case endIndex
}

extension ValidIndexCollectionIndex: Comparable {
    // ...
}

现在我可以扩展ValidIndexCollection

// Implementing the Collection protocol requirements.
extension ValidIndexCollection {

    typealias _Index = ValidIndexCollectionIndex<ValidIndex>

    var startIndex: _Index {
        return firstValidIndex.flatMap { .index($0) } ?? .endIndex
    }

    var endIndex: _Index {
        return .endIndex
    }

    func index(after index: _Index) -> _Index {
        guard case .index(let validIndex) = index else { fatalError("cannot increment endIndex") }
        return .index(self.validIndex(after: validIndex))
    }

    subscript(index: _Index) -> Iterator.Element {
        guard case .index(let validIndex) = index else { fatalError("cannot subscript using endIndex") }
        return element(at: validIndex)
    }

}

一切似乎都很好,编译器没有抱怨!但是,我尝试为自定义类型实现此协议:

struct CollectionOfTwo<Element> {
    let first, second: Element
}

extension CollectionOfTwo: ValidIndexCollection {

    var firstValidIndex: Int? { return 0 }
    var lastValidIndex: Int? { return 1 }

    func validIndex(after index: Int) -> Int {
        return index + 1
    }

    subscript(index: Int) -> Element {
        return index == 0 ? first : second
    }

}

现在编译器抱怨CollectionOfTwo 不符合CollectionSequenceIndexableBase。错误消息非常无用,主要是以下消息:

协议需要嵌套类型SubSequence;要添加吗?

关联类型Indices(来自协议Collection)的默认类型DefaultIndices&lt;CollectionOfTwo&lt;Element&gt;&gt;不符合IndexableBase

有什么办法可以使这个工作吗?据我所知,ValidIndexCollection 可以很好地满足Collection 的要求。

注意事项:

  • 我调用了ValidIndexCollection协议方法 validIndex(after:) 那样是因为称它为index(after:) 尝试实现此协议时导致分段错误。这可能与 来自Collection 协议的index(after:) 方法。

  • 出于同样的原因,我使用 element(at:) 而不是下标。

  • 我使用了typealias _Index 而不是typealias Index,因为后者导致了一条错误消息,指出“Index 在此上下文中的类型查找不明确”。同样,这可能与CollectionIndex 关联类型有关。

【问题讨论】:

    标签: swift protocols swift3 swift-protocols


    【解决方案1】:

    associatedtype Element 添加到ValidIndexCollection 并将所有出现的Iterator.Element 替换为Element 修复了它。

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2017-03-10
      相关资源
      最近更新 更多