Rust exercisesやってみた

# Rust exercisesとは
[Rust exercises](https://github.com/chikoski/rust-exercises)とはgithub上で公開されているrustの練習用問題のようなやつです。rustの難しい概念などを一個ずつピックアップして実装することで理解を深めよう的な趣旨のやつです。
ただ、まとまった模範解答らしきやつは見当たらないので、自分でやってみた実装や自分なりの解釈をまとめてみようと思います。

実装的にはクリアできていてもよりよい書き方やrustらしい書き方があると思うので間違っているところ等ありましたらビシバシご指摘お願いいたします。。🙏

# 1. Hello world
`to_string()`するかどうかぐらいの落とし穴しかなかったので割愛

[1のdiff](https://github.com/Dragon-taro/rust-exercises/commit/6708ba61bfa3492cecdeb62da3bd3aa9b06f6d95)

# 2. 所有権に関するもの
## ゴール1
`push()`しているのに`mut`で宣言されていないので、`mut`で宣言するようにしておけばおk

```rust
let mut result = String::new();
```

## ゴール2
そのまま`text`を渡してしまうと所有権が関数に渡ってしまってそのあとに`text`が使えなくなってしまうので、ここでは一旦`clone()`してコピーを渡すようにしました。これで所有権が失われることはありません。

```rust
let kanji_only = remove_hiragana(text.clone());
```

## ゴール3
コピーせずに関数を実行するには関数が所有権を借用できるようにすればおkです（日本語が合っているか不安）。つまり参照渡しになるように関数を書き換えます。

```rust
fn remove_hiragana(text: &String) -> String {
    // ...
}
```

これで呼び出し元で

```rust
let kanji_only = remove_hiragana(&text);
```

としてやればおkです。

## ゴール4
これがちょっと出題者の意図が汲み取れずにどれが正解かわからない状況です。

```rust
// ゴール4：次の行をアンコメントしても実行できるようにしてください
output(message);
```

とあるので、

```rust
output(&message);
```

とするのはだめという風に解釈して、

```rust
let message = &format!("{}{}！", word_a, word_b);
output(message);
// ゴール4：次の行をアンコメントしても実行できるようにしてください
output(message);

fn output(text: &String) {
  // ..
}
```

という風に実装してみました。ただ、`&String`を変数で持つ意味がない的な話を聞いたので`output(&message);`で渡すか、1回目を`clone()`してあげるだけで良さそうな気がするなという印象です。

[2のdiff](https://github.com/Dragon-taro/rust-exercises/commit/6708ba61bfa3492cecdeb62da3bd3aa9b06f6d95)

# 3. 参照に関するもの
まずは、参照で渡せるようにしました。

```rust
fn main() {
    let name = format!("dear rustaceans");
    greet(&name);
    greet(&name);
}

fn greet(name: &String) {
    println!("Hello {}", name);
}
```
これで、参照を渡しているので実行できるようになります。


## ゴール2
文字列を書き換えればいけるので割愛

## ゴール3
スライスで関数に渡せるようにする必要があるので、`greet()`を以下のように書き換えます。

```rust
fn greet(name: &str) {
    println!("Hello {}", name);
}
```

そして呼び出し元で、

```rust
greet(&name[5..]);
```
としてやると想定通りに動きます。

ちなみに、

```rust
format!("dear rustaceans");
```
は`String`ですが、`greet()`では`&str`で受けっとています。これはrustの型強制という仕様によるもので、これで暗黙の型変換が行われます。（`&str`の指定がされて初めて`&String`から`&str`に変換される）

[3のdiff](https://github.com/Dragon-taro/rust-exercises/commit/6840a2afc674082e24634383fb0b4847ea256f5c)

# 4. 変更可能な参照
## ゴール1, 2, 3

```rust
let (mut word_a, word_b) = words();

// ..

fn concat(prefix: &mut String, postfix: &String) -> String {
    prefix.push(' ');
    for c in postfix.chars() {
        prefix.push(c);
    }
    prefix.to_string()
}
```

このように書き換えました。`&mut`で渡す変数は`mut`で渡す必要があります。（`mut`で渡す場合は所有権がわたるので何で宣言していても問題ない）

また、第一引数をそのままreturnしているので、参照を外す必要があります。`to_string()`をすることで参照が外れます。（正確には中でコピーを作成して返してる感じな気がする）

[4のdiff](https://github.com/Dragon-taro/rust-exercises/commit/8e355a7bed7c9714d0c919c166db985d3b60df34)

# 5. Null返す可能性のある関数
## ゴール1
`unrwap()`したら終わり

## ゴール2
`unrwap()`だけだと`None`のときにpanicしてしまうので、パターンマッチでそれぞれの条件に対応してあげる必要があります。

```rust

fn show_price(name: &str, price: Option<&u32>) {
    match price {
        Some(value) => println!("{}は{}円です", name, value),
        None => println!("{}は登録されていません", name)
    }
}
```

このように実装してやることで、登録されていない場合もエラーを吐くことがなくなります。関数型の書き方なので慣れない人も多いかも？

[5のdiff](https://github.com/Dragon-taro/rust-exercises/commit/f9bf5925ffa710deee4ac5312fd39f90877bfef70)

# 6. エラーを返す可能性のある関数
## ゴール1
`unrwap()`がエラーの巣窟になっているので、またしてもパターンマッチで解決。

```rust
match read_file(&file) {
    Ok(file) => println!("{}", file),
    Err(err) => println!("no such file or directory")
}
```
このようにすると、エラーハンドリングができます。

## ゴール2
```rust
fn read_file2(filename: &String) -> Result<String, String> {
    File::open(filename)
        .map_err(|err| err.to_string())
        .and_then(|mut file| {
            let mut contents = String::new();
            file.read_to_string(&mut contents)
                .map_err(|err| err.to_string())
                .map(|_| contents)
        })
}
```
コンビネーターを使って`Result`をうまく扱うようにしました。
`and_then()`で`Result`を結合したり、`map()`で`Ok`のときだけの処理を書いたり、`map_err()`で`Err`のときだけの処理を書いています。

ただしこの書き方だと`try!`が使えなかったり、早期リターンができなかったりとデメリットもあるようです。個人的には関数型にそこまで慣れていないということもあり、手続き的に書く方が好きかなという印象です。

[6のdiff](https://github.com/Dragon-taro/rust-exercises/commit/0b605219263b4ba7859b591bcfc4f9ea1fa8b880)