Rustの標準入力に躓いた

# 標準入力
Rustの勉強を進めるなかで標準入力に躓きました。
標準入力の実装方法はわかったけれど、どういう意味を持ったコードかわからなかったので自分なりに調べたことを書いていきます。
同じく標準入力で困った人のお役に立てれば・・・


# 文字を受け取る
まずは、文字を受け取ってその文字を出力します。
```rust
use std::io;

fn main()
{
    let mut word = String::new();
    io::stdin().read_line(&mut word).expect("F");
    println!("input word = {}", word.trim());
}
```

おそらく一番簡単な実装方法はこれです。
実行結果はこちら。
```terminal
hello
input wprd = hello
```
## use std::io;
```rust
use std::io;
```
標準ライブラリのioモジュールをインポートするためのおまじないです。
でstdライブラリを読み込んでいます。C言語でいうところの`#include <stdio.h>`、Pythonでいう`import flet as ft`みたいなものですかね。
標準入力ではioモジュールを使用するため、このおまじないを書いておく必要があります。

## let mut word = String::new();
```rust
let mut word = String::new();
```
これで空の文字列(Strin型)を準備しています。
この変数の箱に入力された文字を入れるので、`let mut`を使って可変の変数にしておく必要性があります。
`String::new()`で**String型の空のオブジェクトを作成**、これを変数`word`に代入します。

## io::stdin().read_line(&mut word).expect("F");
```rust
io::stdin().read_line(&mut word).expect("F");
```
>Constructs a new handle to the standard input of the current process.
引用元: [Rust Programing Language](https://doc.rust-lang.org/std/io/fn.stdin.html)

とあるように、`io::stdin()`というのは、標準入力のハンドルを構築します。つまり、`io::stdin()`で標準入力の意味を表します。C言語でいう`scanf関数`とほぼ似たような感じですね。

#### .read_line()
入力された１行をwordという変数の箱に入れてあげるためのものです。
`&mut word`は、wordに文字列を書き込んでいいよ！！という**可変参照**を渡しています。
可変参照では、参照先の値を読み出し変更することができます。
最初にwordという変数を空の文字列で作っているので、そこを変更します。

#### .expect()
正しく入力ができなかった時にエラーを出してプログラムを終了させるためのものです。
この部分はなくても動きます。

これで最低限の標準入力の実装の完成です。
#### .trim()
`.trim()`は改行を取り除くという意味を持ちます。
なので、 word に含まれる改行を消してくれます。
```rust
print!("input number= {}", word);
```
という書き方でも、最後の段に空の改行なしで出力されます。

# 入力前に文を表示
上のやり方で必要最低限の標準入力の実装は可能です。
```terminal
hello
input wprd = hello
```
しかし表示のされ方がすこしわかりにくいですね。
なので文字の入力を受け取る前に、文を表示しておきます。
```rust
use std::io;
use std::io::Write;

fn main()
{
    print!("input word: ");
    io::stdout().flush().unwrap();

    let mut word = String::new();
    io::stdin().read_line(&mut word).expect("F");
    println!("input wprd = {}", word.trim());
}
```
```terminal
input word: hello
input wprd = hello
```
わかりやすくなりましたね。
では、それぞれ何をしているのかについて書いていきます。
## use std:: io::Write;
ioと両サイドの::で国旗に変換されちゃう;;
これは、ioモジュールの中にあるWriteという機能を使えるようにするおまじないです。
後述の``.flush()``を使うために必要になります。
文字の出力を細かく管理したりするために必要なルールがまとまっています。

## io::stdout().flush().unwrap();
#### io::stdout()
>Constructs a new handle to the standard output of the current process.
[Rust Programing Language](https://doc.rust-lang.org/std/io/fn.stdout.html)

`io::stdin()`は標準入力のハンドルを構築していましたが、`io::stdout()`では標準出力のハンドルを構築しています。

#### .flush()
これは**ため込んでいる出力データを一気に外に出す**ための命令です。
`print!`などの書き込みはすぐに出力されません。そのため、.flush()をもちいて、`print!`で出力させた文をすぐに表示させています。

#### .unwrap()
これは、成功していればそのままプログラムを実行、失敗していればプログラムを終了させるためのものです。

では、`io::stdout().flush().unwrap()`がないとどのように表示されるのでしょうか。
```terminal
hello
input word: input wprd = hello
```
このように`input word`が標準入力を受け取った後に表示されてしまします。

ちなみに、prinln!の場合、`io::stdout().flush().unwrap()`がなくても`input word`が標準入力の前に表示できます。
```terminal
input word: 
hello
input wprd = hello
```
このように`input word`の後に改行が含まれます。`println!`には、改行の要素が含まれているため`.flush()`が自動的に行われます。

# 数値を受け取る
今までは文字列を受け取り、文字列を出力してきました。
数字を入力してその数字が奇数か偶数か判断するといった問題をみたことがある人も多いと思います。
Rsutでの数値の入力の仕方を書いていきます。
```rust
use std::io;
use std::io::Write;

fn main()
{
    print!("input number: ");
    io::stdout().flush().unwrap();

    let mut word = String::new();
    io::stdin().read_line(&mut word).expect("F");
    let num: i32 = word.trim().parse().expect("F");
    
    if num % 2 == 0 {
        println!("偶数");
    }else {
        println!("奇数");
    }
}
```
```terminal
input number: 6
偶数
```
## let num: i32 = word.trim().parse().expect("F");
文字列を数値に変換して変数に入れるという作業をしています。
Rustは静的型付け言語なので、変数の型を変換してあげる必要があります。

#### word.trim()
入力された文字列が入っている変数`word`には改行も含まれています。その改行をなくすためのものです。
`trim()`の部分が改行の削除に当たります。

#### .parse()
これは、文字列を別の型に変換しています。
変数`word`はString型の文字列なのでこれをi32型(数値型)の数字に変換します。
数値に変換しなければ、大きさを比べたり四則演算ができないので必要な処理です。
(ChatGPT君によれば、内部のエラーチェックもしてくれているらしい。parseに`解析`という意味があるから納得)

#### let num: i32 
上記の処理が正常に終了し、型変換に成功したら、i32型の変数`num`に格納します。`i32`とはＣ言語でいう`int`のようなものです。細かな違いはありますが両方整数のみを受け取るという点で共通しています。
`.parse()`を用いた場合は変換先の変数の型を明示する必要があるので、ここで変数の型をしっかり指定しておきましょう。
数値型の変数`num`をもちいて、奇数偶数の判定を行っていきます。

# 参考

https://ittrip.xyz/rust/rust-unwrap-expect-guide

https://terminart-express.site/archives/4141