今年も岩手県立大学アドベントカレンダーを書きます!
Swiftでzipメソッドを使うことはあると思いますが、引数として取れる値の数は2つのみです。
今回は3つの引数をとれるzipメソッドを実装したので紹介します。
環境
$ swift --version
Apple Swift version 5.1 (swift-5.1-RELEASE)
Target: x86_64-apple-darwin19.2.0
実装
func zip<A: Sequence, B: Sequence, C: Sequence>(_ a: A, _ b: B, _ c: C) -> Zip3Sequence<A, B, C> {
Zip3Sequence(a, b, c)
}
struct Zip3Sequence<A: Sequence, B: Sequence, C: Sequence>: Sequence, IteratorProtocol {
private var a: A.Iterator
private var b: B.Iterator
private var c: C.Iterator
init (_ a: A, _ b: B, _ c: C) {
self.a = a.makeIterator()
self.b = b.makeIterator()
self.c = c.makeIterator()
}
mutating func next() -> (A.Element, B.Element, C.Element)? {
guard let a = a.next(), let b = b.next(), let c = c.next() else { return nil }
return (a, b, c)
}
}
解説
簡単にながら解説を書きます。
Swiftのzipメソッドは二つのSequenceを引数にとり、Zip2Sequenceを返却します。zip(::) - Swift Standard Library | Apple Developer Documentation
また、このZip2SequenceもSequenceプロトコルに準拠しています。 Zip2Sequence - Swift Standard Library | Apple Developer Documentation
リファレンスを参考にSequenceプロトコルに準拠した、Zip3Sequenceを作成しました。
Sequence - Swift Standard Library | Apple Developer Documentation に書いていますが、Sequenceプロトコルに準拠するためには func makeIterator() -> Self.Iterator
を実装するか、 IteratorProtocol
に準拠する必要があるとの記載があります。
Making your own custom types conform to Sequence enables many useful operations, like for-in looping and the contains method, without much effort. To add Sequence conformance to your own custom type, add a makeIterator() method that returns an iterator.
Alternatively, if your type can act as its own iterator, implementing the requirements of the IteratorProtocol protocol and declaring conformance to both Sequence and IteratorProtocol are sufficient.
今回はIteratorProtocolに準拠して実装をしました。
Zip3Sequenceに渡している3つのSequenceですが、このプロトコルに準拠しているものは makeIterator() というメソッドを持っているため、作成したイテレータに対してnext()を呼ぶごとにシーケンスの次の値を参照することができます。
IteratorProtocolに準拠するためには func next() -> Self.Element?
を実装すれば良いです。 IteratorProtocol - Swift Standard Library | Apple Developer Documentation
理解がし辛い方へ補足を入れると、Zip3Sequence自身も next() メソッドを持っているし、 引数として渡されている3つのSequenceも next() メソッドを持っています。
next() メソッドはmutating funcであり自身に対して作用するためvarとして宣言する必要があります。
まとめ
この記事では3つの引数を取れるzipメソッドの実装について紹介しました。
間違っている箇所やご意見があればお願いします。
ジェネリクスを用いて引数の数に限りがないメソッドを作れるのかについても調査してみます。
最後までご覧いただきありがとうございました。