2016-08-17 8 views
2

これまでSwiftにバイナリ検索ツリータイプを作成しましたが、私はCollectionプロトコルに準拠させたいと考えていました。しかし、endIndexの要件は、各インデックスがO(1)アクセスの対応するノードへの参照を保持する必要があるため、ツリーには実際には適切でない「過去の終わり」インデックスです。私はオプションのリファレンス(の場合はnil)になってしまったが、それはむしろ避けたい定型コードをたくさん含んでいた。SwiftでValidIndexCollectionプロトコルを作成する3

私はこのようになりますValidIndexCollectionプロトコル作ることを決めた:私はCollection要件を満たすために、このプロトコルを拡張することができます前に、私が最初に適切な指標を導入する必要が

/// 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 

} 

を:

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 
    } 

} 

今コンパイラがCollectionOfTwoCollectionSequence、およびIndexableBaseに準拠していないことに文句を言います。エラーメッセージは非常に役に立ちません。ほとんどのメッセージは次のとおりです。

プロトコルにはネストタイプが必要ですSubSequence;あなたはそれを追加したいですか?

または

(プロトコルCollectionから)関連するタイプIndicesのデフォルトタイプDefaultIndices<CollectionOfTwo<Element>>IndexableBase

に準拠していないこの作品を作るための方法はありますか?私が言う限り、ValidIndexCollectionCollectionの要件を満たしています。

には、いくつかの注意事項:

  • このプロトコルを実装しようとしたときにindex(after:) それを呼び出すと、セグメンテーションフォールトが生じたので、私はValidIndexCollectionプロトコル方式 validIndex(after:)そのように呼ばれます。おそらく、Collectionプロトコルの index(after:)メソッドと関係があります。

  • 同じ理由で私はサブスクリプトの代わりにelement(at:)を使用しました。

  • typealias Indexの代わりにtypealias _Indexを使用しました。これは、「Indexがこのコンテキストでタイプルックアップにあいまいです」というエラーメッセージが表示されたためです。この場合も、CollectionIndex関連タイプと関連があります。

答えて

1

ValidIndexCollectionassociatedtype Elementを追加し、それを修正することによってElementIterator.Elementのすべての発生を置き換えます。

関連する問題