[Rust] RustでFizzBuzz書いてみる

https://qiita.com/gyu-don/items/aa61c5bbc1017bd3171c

これを見て、なるほど、と思ったので書いてみることにした。

## パターン１ まずは自分なりに書いてみる
FizzとBuzzとFizzBuzzをそれぞれ以下のように考える

- Fizz
	- 3で割り切れるならFizzっていう人
- Buzz
	- 5で割り切れるならBuzzっていう人
- FizzBuzz
	- FizzとBuzzの組み合わせ

```rust
pub struct Fizz {
    values: [Option<&'static str>; 3],
}

impl Fizz {
    pub fn new() -> Fizz {
        Fizz { values: [Some("Fizz"), None, None] }
    }

    fn get(&self, i: usize) -> Option<&'static str> {
        self.values[i%3]
    }
}

pub struct Buzz {
    values: [Option<&'static str>; 5],
}

impl Buzz {
    pub fn new() -> Buzz {
        Buzz { values: [Some("Buzz"), None, None, None, None] }
    }
    fn get(&self, i: usize) -> Option<&'static str> {
        self.values[i%5]
    }
}

fn main() {
    let fizz = Fizz::new();
    let buzz = Buzz::new();

    for i in 1..50 {
        match (fizz.get(i), buzz.get(i)) {
            (None, None) => println!("{}", i),
            (fizz, buzz) => println!("{}{}", fizz.unwrap_or_default(), buzz.unwrap_or_default()),
        }
    }
}
```

割り切れるかどうか、ではなくて、剰余をindexとして使いたかったので、配列として持っている。

本当は定数として、構造体のfieldに持って `Buzz::get(i)` のような感じにしたかったけど、
~~構造体の中で `static` や `const` はできないらしい。~~
[修正] [1.20(stable)以降ではAssociated constで実現できる](https://qiita.com/yagince/items/6f9c082f639d0c833f79#comment-554cdd3889e9fa9643c8)

やるとしたら、こんな感じだろうか。

```rust
const FIZZ_VALUES: [Option<&'static str>; 3] = [Some("Fizz"), None, None];
const BUZZ_VALUES: [Option<&'static str>; 5] = [Some("Buzz"), None, None, None, None];

pub struct Fizz;
impl Fizz {
    fn get(i: usize) -> Option<&'static str> {
        FIZZ_VALUES[i%3]
    }
}

pub struct Buzz;
impl Buzz {
    fn get(i: usize) -> Option<&'static str> {
        BUZZ_VALUES[i%5]
    }
}

#[cfg(test)]
mod tests {
    use super::*;

    #[test]
    fn fizzbuzz() {
        for i in 1..50 {
            match (Fizz::get(i), Buzz::get(i)) {
                (None, None) => println!("{}", i),
                (fizz, buzz) => println!("{}{}", fizz.unwrap_or_default(), buzz.unwrap_or_default()),
            }
        }
    }
}
```

## パターン２

[冒頭で触れた記事](https://qiita.com/gyu-don/items/aa61c5bbc1017bd3171c)のトレイトの使い方になるほど感があったので、マネしてみる。

- FizzとBuzzは、同じ種類と考える
	- つまりEnumだ
- Fizz(Buzz)がどう発言するか
	- つまり、Displayトレイトだ
- iがどういう時に、Fizzになるか、Buzzになるか
	- つまり、Fromトレイトだ
	- `x.into()` って書けるとカッコイイ


```rust
use std::fmt;

enum FizzBuzz {
    Fizz,
    Buzz,
    FizzBuzz,
    Num(u32),
}

impl fmt::Display for FizzBuzz {
    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
        match self {
            &FizzBuzz::Fizz     => write!(f, "Fizz"),
            &FizzBuzz::Buzz     => write!(f, "Buzz"),
            &FizzBuzz::FizzBuzz => write!(f, "FizzBuzz"),
            &FizzBuzz::Num(i)   => write!(f, "{}", i),
        }
    }
}

impl From<u32> for FizzBuzz {
    fn from(n: u32) -> FizzBuzz {
        match (n%3, n%5) {
            (0, 0) => FizzBuzz::FizzBuzz,
            (0, _) => FizzBuzz::Fizz,
            (_, 0) => FizzBuzz::Buzz,
            _      => FizzBuzz::Num(n),
        }
    }
}

fn main() {
    (1..50)
        .map(|x| x.into())
        .for_each(|r: FizzBuzz| println!("{}", r) )
}
```

すこしシンプルになったかな？

## `Into<U> for T` と `From<T> for U`

↑では `From<T>` を実装したことで `into()` が使えるようになった。
でも、ここで疑問

[Into<T>](https://doc.rust-lang.org/std/convert/trait.Into.html) を実装するのと、何が違うんだろうか

[From<T>](https://doc.rust-lang.org/std/convert/trait.From.html)には

https://doc.rust-lang.org/std/convert/trait.From.html#generic-implementations
> From<T> for U implies Into<U>for T
> from is reflexive, which means that From<T> for T is implemented

と書かれている。

https://doc.rust-lang.org/src/core/convert.rs.html#410

```rust
// From implies Into
#[stable(feature = "rust1", since = "1.0.0")]
impl<T, U> Into<U> for T where U: From<T>
{
    fn into(self) -> U {
        U::from(self)
    }
}
```
ここかな？

`From<T> for U` 
というのは
`TからUへ変換することができる`
ということで

それはつまり
`TはUになることが出来る`
ということで、暗黙的に
`Into<U> for T`
となることができるはず

っていうことですかね？

つまり、

```rust
impl Into<Hoge> for Foo {
  …
}
```
を手で書くことはほとんどなくて、それがやりたい時はFromを実装する。

`Into`を使う場面は、型指定で、`特定の何かにintoできるもの` というのを表現したい時に使う。

と理解しておけばいいのだろうか？

今回のケースでいうと

```rust
fn print_fizzbuzz<T: Into<FizzBuzz>>(x: T) {
    println!("{}", x.into())
}

fn main() {
    (1..50).for_each(|x| print_fizzbuzz(x) )
}
```

こんな感じでしょうか。