FizzBuzzで学ぶSwift


[Swiftで作るToDoアプリ開発チュートリアルを見ながらToDoアプリを作った](http://qiita.com/dondoko-susumu/items/8c76f01562ee5982fa8c)(2016/6/4)
↑の記事から始まり、本格的にSwiftに触れ３ヶ月経ち、今では`as`やら`?`やら`!`も読み取れるようになった。
というわけで、今一度基本に立ち返り、`FizzBuzz`を題材にして`Swift(2.2)`を学んでいく。

## FizzBuzzとは
1から100までの数字を見て、3で割り切れれば`Fizz`、5で割り切れれば`Buzz`、両方で割り切れれば`FizzBuzz`、それ以外なら数字そのものを出力するというプログラム。元々は言葉遊びのゲームらしいが、私は１度もやったことがない。

## 素朴なFizzBuzz

```swift
for n in 1...100 {
    if n % 15 == 0 {
        print("FizzBuzz");
    } else if n % 5 == 0 {
        print("Buzz")
    } else if n % 3 == 0 {
        print("Fizz")
    } else {
        print(n)
    }
}
```
FizzBuzzの説明をそのままコードで表現。

## 関数定義でFizzBuzz

```swift
func fizzbuzz(n:Int) -> String {
    if n % 15 == 0 { return "FizzBuzz" }
    if n %  5 == 0 { return "Buzz" }
    if n %  3 == 0 { return "Fizz" }
    return String(n)
}

for n in 1...100 {
    print(fizzbuzz(n))
}
```

関数により数字をFizzBuzz化する処理(モデル)と出力する部分(ビュー)を分けている。

## extensionでFizzBuzz
```swift
extension Int {
    func fizzbuzz() -> String {
        if self % 15 == 0 { return "FizzBuzz" }
        if self %  5 == 0 { return "Buzz" }
        if self %  3 == 0 { return "Fizz" }
        return String(self)
    }
}

for n in 1...100 {
    print(n.fizzbuzz())
}
```
「数値を文字列にする関数」という考え方から「数値自身に、文字列化するメソッドを持たせる」というオブジェクト指向の考え方に進化。`extension`は型を拡張する機能。SwiftでiOSアプリを書いていると、extension祭りになるほど強力だ。

## getterでFizzBuzz

```swift
extension Int {
    var fizzbuzz:String {
        if self % 15 == 0 { return "FizzBuzz" }
        if self %  5 == 0 { return "Buzz" }
        if self %  3 == 0 { return "Fizz" }
        return String(self);
    }
}

for n in 1...100 {
    print(n.fizzbuzz)
}
```
getterを用いてメソッド末尾の`()`を取り除いた形。getterは変数のふりをしたメソッド。

## subscriptでFizzBuzz

```swift
class FizzBuzz {
    subscript (n:Int)->String {
        if n % 15 == 0 { return "FizzBuzz" }
        if n %  5 == 0 { return "Buzz" }
        if n %  3 == 0 { return "Fizz" }
        return String(n)
    }
}

let fizzbuzz = FizzBuzz()
for n in 1...100 {
    print(fizzbuzz[n])
}
```
subscript(添字定義)でメソッドを定義し、`[]`にIndexを指定して配列のように結果を取得。subscriptによって、配列のふりをしたオブジェクトが作れる。

## オブジェクト全体をイテレートしてFizzBuzz
```swift
extension FizzBuzz : SequenceType {
    func generate() -> AnyGenerator<String>  {
        var n = 0
        return AnyGenerator<String> {
            if n == 100 {return nil}
            n += 1
            return self[n]
        }
    }
}

let fizzbuzz = FizzBuzz()
for s in fizzbuzz {
    print(s)
}
```
`for in`ループでイテレートさせるために`SequenceType`プロトコルに適合させる。`map`や`filter`もできるようになる。ジェネリクスにはついてはまだあまり理解してない。

## オプショナルでFizzBuzz

```swift
let fizzbuzz = [
    3:"Fizz",5:"Buzz",6:"Fizz",9:"Fizz",
    10:"Buzz",12:"Fizz",0:"FizzBuzz"
]

for n in 1...100 {
    print(fizzbuzz[n % 15] ?? String(n))
}
```
連想配列を使用したFizzBuzzだが、`print`する際オプショナルの性質を利用している。オプショナルは「値なしがあり得る型」で`??　String (n)`の部分を削除すると、キーのあるところは`Optional("")`、ないところは`nil`と表示される。`??`は左辺がnilなら、右辺の値という意味。`fizzbuzz[n]`がオプショナル型ではなくStringだと、nに対応する値がない場合に困ってしまうのでオプショナルを利用する。

## 俺たちの戦いは続く
`swift fizzbuzz`でググるとトップに出てくる下記記事のコードを見ても、何をやってるのかがわからなかった（fizzbuzzをしてるのはもちろんわかるのだが）Swiftマスターへ続く道はまだまだ長そうだ。
[Swiftで関数型FizzBuzz](http://qiita.com/koher/items/74b71242a1ca3b87abcf)

## 参考
Software Design Vol.2014/12 「小飼弾の書いて覚えるSwift入門」
[SequenceTypeの利便性 in Swift 2.2](http://tech.vasily.jp/entry/swift_sequence_2_2)