これまで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
}
}
今コンパイラがCollectionOfTwo
がCollection
、Sequence
、およびIndexableBase
に準拠していないことに文句を言います。エラーメッセージは非常に役に立ちません。ほとんどのメッセージは次のとおりです。
プロトコルにはネストタイプが必要です
SubSequence
;あなたはそれを追加したいですか?
または
(プロトコル
Collection
から)関連するタイプIndices
のデフォルトタイプDefaultIndices<CollectionOfTwo<Element>>
はIndexableBase
に準拠していないこの作品を作るための方法はありますか?私が言う限り、ValidIndexCollection
はCollection
の要件を満たしています。
には、いくつかの注意事項:
このプロトコルを実装しようとしたときに
index(after:)
それを呼び出すと、セグメンテーションフォールトが生じたので、私はValidIndexCollection
プロトコル方式validIndex(after:)
そのように呼ばれます。おそらく、Collection
プロトコルのindex(after:)
メソッドと関係があります。同じ理由で私はサブスクリプトの代わりに
element(at:)
を使用しました。typealias Index
の代わりにtypealias _Index
を使用しました。これは、「Index
がこのコンテキストでタイプルックアップにあいまいです」というエラーメッセージが表示されたためです。この場合も、Collection
のIndex
関連タイプと関連があります。