この記事は何?
SwiftのSequenceプロトコルについて、解説したものです。
開発者ドキュメントより
宣言
protocol Sequence<Element>
概要
シーケンスは、1つずつ連続して取得できるリスト形式の値です。
シーケンスの要素を反復処理する代表的な方法は、for-in
ループです。
let oneTwoThree = 1...3
for number in oneTwoThree {
print(number)
}
// Prints "1"
// Prints "2"
// Prints "3"
これによって、どんなシーケンスに対しても、多くの操作方法を実行できるようになります。
例えば、シーケンスに特定の値が含まれているかどうかを確認するために、「値が一致するか、シーケンスの最後に到達する」まで、各値を順次チェックできます。
次の例では、昆虫の配列に「蚊がいるかどうか」を確認します。
let bugs = ["Aphid", "Bumblebee", "Cicada", "Damselfly", "Earwig"]
var hasMosquito = false
for bug in bugs {
if bug == "Mosquito" {
hasMosquito = true
break
}
}
print("'bugs' has a mosquito: \(hasMosquito)")
// Prints "'bugs' has a mosquito: false"
Sequence
プロトコルは、シーケンスから値を順次取得する一般的な操作のデフォルト実装を提供します。
上記の例のように手動で反復せずに、すべてのシーケンスがSequence
プロトコルから継承する配列のcontain(_:)
メソッドを使用すると、コードをより明確で簡潔にできます。
if bugs.contains("Mosquito") {
print("Break out the bug spray.")
} else {
print("Whew, no mosquitos!")
}
// Prints "Whew, no mosquitos!"
連続のアクセス
Sequence
プロトコルは、反復によって「データが破損されるかどうか」について、適合する型に要求しません。その結果、あるシーケンスがfor-in
ループをいくつも反復したり、初めから再回したりすると仮定はしません。
for element in sequence {
if ... some condition { break }
}
for element in sequence {
// No defined behavior
}
この場合では、シーケンスが消耗されて反復を再開するか、シーケンスがコレクションなので先頭要素から反復を再開するか、を仮定することはできません。
コレクションではないSequence
適合型は、2番目のfor-in
ループで任意の要素のシーケンスを生成できます。
型の非破壊的な反復をサポートを確認するには、その型をCollection
プロトコルに準拠させます。
Sequenceプロトコルに準拠する
独自の型をSequence
に準拠させると、for-in
ループやcontains
メソッドなど、多くの便利な操作ができるようになります。
型をSequence
プロトコルに準拠させるには、イテレータを返すmakeIterator()
メソッドを実装します。
なお、型が独自のイテレータとして機能できる場合は、IteratorProtocol
プロトコルの要件を実装し、Sequence
とIteratorProtocol
の適合を宣言するだけです。
以下に、独自のイテレータとして機能するカウントダウンのシーケンスを定義します。
makeIterator()
メソッドは、デフォルト実装が提供されます。
struct Countdown: Sequence, IteratorProtocol {
var count: Int
mutating func next() -> Int? {
if count == 0 {
return nil
} else {
defer { count -= 1 }
return count
}
}
}
let threeToGo = Countdown(count: 3)
for i in threeToGo {
print(i)
}
// Prints "3"
// Prints "2"
// Prints "1"
計算量
シーケンスが提供するイテレータの計算量はO(1)
である必要があります。
Sequence
プロトコルは、要素を取得する方法については他の要件はないので、特に文書化されていない限り、シーケンスを横断するルーチンはO(n)
と見なすべきです。