0
4

More than 1 year has passed since last update.

【Swift】公式ドキュメントのSequenceプロトコルを読む

Last updated at Posted at 2022-10-15

この記事は何?

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プロトコルの要件を実装し、SequenceIteratorProtocolの適合を宣言するだけです。

以下に、独自のイテレータとして機能するカウントダウンのシーケンスを定義します。
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)と見なすべきです。

0
4
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
0
4