SwiftでIteratorパターン

最近は、もっぱら言語レベルでサポートされるようになってしまった Iterator です。

増補改訂版Java言語で学ぶデザインパターン入門』では、記念すべき最初の章で紹介されるパターンです。堅物な(?) Java 向けの解説ということもあり、この本の Iterator パターンの章では、クラスやインタフェースが不自然なほど*1登場しますが、Swift はやや言語仕様が洗練されたこともあり、かなり自然に Iterator パターンを適用できます。

独自クラスでインデクサ [ ] とか for-in 構文とかを使えるようにするためのヒントになるかも。あまりヒントっぽくないかも。

ちなみに動作確認は Xcode 6 beta 5 で行っています。これより古い(または新しい)バージョンの Xcode では動かないかも知れません。

// ----------------------------------------
// Book (本) クラス
public class Book {
    private var _name: String
    
    public var name: String {
        get {
            return _name
        }
    }
    
    public init(name: String) {
        self._name = name
    }
}

// ----------------------------------------
// BookShelf (本棚) クラス
// SequenceTypeプロトコルを採用するのがチャームポイント
public class BookShelf: SequenceType {
    private var books:[Book] = []
    
    // プロパティさんです
    public var capacity: Int {
        get { return books.capacity }
    }
    
    public var startIndex: Int {
        get { return books.startIndex }
    }
    
    public var endIndex: Int {
        get { return books.endIndex }
    }
    
    public var count: Int {
        get { return books.count }
    }
    
    // インデクサ [ ] でアクセスできるようになるよ
    public subscript(index: Int) -> Book {
        get { return books[index] }
        set { books[index] = newValue }
    }
    
    public subscript(range: Range<Int>) -> Slice<Book> {
        get { return books[range] }
        set { books[range] = newValue }
    }
    
    // for-inでアクセスできるようになるよ
    public func generate() -> GeneratorOf<Book> {
        var index : Int = 0
        return GeneratorOf<Book> {
            return index < self.books.count ? self.books[index++] : .None
        }
    }
    
    // ↑の代わりに↓みたいに書いてもOK
    // ※ Arrayに委譲する書き方だよ
    // public func generate() -> IndexingGenerator<[Book]> {
    //     return books.generate()
    // }

    
    public func append(book: Book) {
        books.append(book)
    }
}

// ----------------------------------------
var bookShelf = BookShelf()
bookShelf.append(Book(name: "ももたろう"))
bookShelf.append(Book(name: "きんたろう"))
bookShelf.append(Book(name: "たーせるの大冒険"))

// [ ]でアクセスしてみるテスト
for var i = 0; i < bookShelf.count; ++i {
    println(bookShelf[i].name)
}

for i in bookShelf.startIndex ..< bookShelf.endIndex {
    println(bookShelf[i].name)
}

// というか for-in 構文でアクセスできる
for book in bookShelf {
    println(book.name)
}

*1:あくまでSwift目線から見たときの印象ですよ。

Copyright (c) 2012 @tercel_s, @iTercel, @pi_cro_s.