ことわざプログラミング: 1. "時は金なり"


# はじめに
"ことわざをプログラミング"することで Rust を勉強していきます．

## 本日のお題: 時は金なり
> 西洋のことわざ「Time is money.」から。
時間は貴重なものであって、金銭と同じように大切で価値があるのだから、浪費するものではないという戒め。
時間は無駄に費やすものではなく、有効に使うべきである。
http://kotowaza-allguide.com/to/tokiwakanenari.html

## 本日の学び
* 標準入力 `std::io`
* 変数のキャスト
* ２つの文字列型: `&str` と `String`
* 時間に関するモジュール `std::time` の使い方
* 標準出力 `println!`マクロ

## GitHub レポジトリ
https://github.com/skyshk/time_is_money

# 仕様
1. 標準入力から時給を文字列入力
2. 時給文字列から"秒給"を算出
3. 一秒ごとに，「無駄に過ごした時間で稼げるはずだったお金」を標準出力

# コード全体
```rust:time_is_money
// Proverb Programming: "Time is money"
// Count duration time, convert it to money, and display.

use std::time;
use std::io;

fn main() {
  println!("Please input your hourly wage:");
  let mut hourly_wage_string = String::new();
  io::stdin().read_line(&mut hourly_wage_string)
              .expect("Failed to read line");
  hourly_wage_string = hourly_wage_string.trim_right().to_string();
  println!("Your hourly wage is :{}",hourly_wage_string);
  let hourly_wage: f32 = hourly_wage_string.parse().unwrap();
  let second_wage: f32 = hourly_wage/60.0/60.0;

  // Count time in second
  let start_time = time::Instant::now();
  let mut count_second:u64 = 0;
  loop {
    if count_second <= start_time.elapsed().as_secs() {
      count_second += 1;
      println!("You have wasted {:.0} secs. = {:.3} Yen",count_second,second_wage* (count_second as f32) );
    }
  }
}
```

# 実行結果
```bash
$./time_is_money
Please input your hourly wage: 
907 # 時給を入力すると...
Your hourly wage is :907
# 起動から現在までに消費した時間 (duration) と，
# そこで得られるはずだったお金が一秒ごとに可視化されます
You have wasted 1 secs. = 0.252 Yen 
You have wasted 2 secs. = 0.504 Yen
You have wasted 3 secs. = 0.756 Yen
You have wasted 4 secs. = 1.008 Yen
You have wasted 5 secs. = 1.260 Yen
You have wasted 6 secs. = 1.512 Yen
You have wasted 7 secs. = 1.764 Yen
You have wasted 8 secs. = 2.016 Yen
You have wasted 9 secs. = 2.268 Yen
You have wasted 10 secs. = 2.519 Yen
You have wasted 11 secs. = 2.771 Yen

...

```

# コードの解説
## 1. 標準入力から時給を入力

まずは，時とお金を変換するための「時給」を入力させます．

Rust では標準入力の受け付けは以下のようにするらしいです．

```rust
let mut hourly_wage_string = String::new();
io::stdin().read_line(&mut hourly_wage_string)
          .expect("Failed to read line");
```
参考: https://doc.rust-lang.org/book/guessing-game.html#processing-a-guess


`io::stdin().read_line()` が本丸の標準入力処理を担います．
`read_line()` の引数には，標準入力を受け取る `String` 型のオブジェクトが必要です．
ですので，予め次のように文字列を受け取るための `String` インスタンスを生成しておきます．

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

これは mutable でなくてはいけません．

こうして生成した空の`hourly_wage_string`文字列インスタンスを，

```rust
io::stdin().read_line(&mut hourly_wage_string)
```

のように引数に渡します．
`&mut`は「`hourly_wage_string`の所有権を関数に借用させます，しかもその内容は変更可です」といった意味らしいです
(参考: https://doc.rust-lang.org/book/references-and-borrowing.html#mut-references)．
※ 所有権・借用の概念はRustの根幹的概念ですが，まだまだ理解しきれていないところがあるので，後々勉強したいですね．

その次の行の

```rust
.expect("Failed to read line");
```

は例外処理で，`read_line` 関数が正しく処理されなかった時に引数のメッセージを出力して落ちるようになっています．

## 2. 時給文字列から"秒給"を算出
さて，受け取った時給は扱いにくいので，秒給に変換してやりたいです．
ただし`hourly_wage_string`は`String`型なので，これを計算可能な数値型にしてやる必要があります．

```rust
hourly_wage_string = hourly_wage_string.trim_right().to_string();
let hourly_wage: f32 = hourly_wage_string.parse().unwrap();
let second_wage: f32 = hourly_wage/60.0/60.0;
```

一番最後の行は単純に時給`hourly_wage`を秒給`second_wage`に変換しているだけです．
その手前二行で，入力された文字列`hourly_wage_string`を浮動小数点`hourly_wage`に型変換（キャスト）しています．

ここで一つ落とし穴が．
最初は標準入力から渡ってきた`hourly_wage_string`を直接なんとかキャストしようと試みましたが，どうしてもエラーになりうまくいきませんでした．

ここでよくよく調べてみると，標準入力から渡ってきた
`hourly_wage_string`には，数値の文字列だけでなく末尾に改行文字列`\n`が含まれており，
これが型変換の邪魔をしていました．
なので型変換をする前に，`String`クラスの`trim_right`メソッドで末尾の邪魔な文字列（空白，`\n`など）を削除しています:

```rust
hourly_wage_string = hourly_wage_string.trim_right().to_string();
```

これはPythonで言うところの`str.strip`メソッドですね．
`trim_right`メソッドの返り値は`String`型とは似て非なる`&str`型なので，
これを`to_string`メソッドで再度`String`型に戻してやります．
※ どうしてRustには２つの文字列型があるのか，まだご利益は感じられていないのが現状です．．．

こうして末尾の`\n`が削除されて数値文字列だけになったはずの`hourly_wage_string`文字列．これを`String`型の`parse`メソッドを使って浮動小数点である`f32`型にキャストします．

```rust
let hourly_wage: f32 = hourly_wage_string.parse().unwrap();
```

`parse`メソッドの返り値は，キャストされた数値そのものではなく，`Result`型と呼ばれる返り値用の特殊な型です．欲しい返り値本体はこの`Result`型の内部に包まれている（`wrap`）ので，解いてやる(`unwrap`)してやることで得ることができます．


## 3. 一秒ごとに，「無駄に過ごした時間で稼げるはずだったお金」を標準出力
秒給を得られたら，一秒ごとに，そこまでの経過時間と，それを秒給で換算した金額を永遠に出力します．
ここで肝となるのは，時間を司る[`std::time`モジュール](https://doc.rust-lang.org/std/time/index.html)を使いこなすことです．

```rust
use std::time;
let start_time = time::Instant::now();
let mut count_second:u64 = 0;
loop {
    if count_second <= start_time.elapsed().as_secs() {
      count_second += 1;
      println!("You have wasted {:.0} secs. = {:.3} Yen",count_second,second_wage* (count_second as f32) );
    }
}
```

まず，最初の時間を取得します．

```rust
let start_time = time::Instant::now();
```

`start_time`は`time::Instant`型と呼ばれる構造体のインスタンスです．
直感的には，あるシステム時間のスナップショット的なオブジェクトです．

`time::Instant`型の構造体には`elapsed`メソッドというものが実装されており，
これを呼び出すと`time::Instant`が作成された時間からの経過時間(duration)が返ってきます．

```rust
let duration: Duration = start_time.elapsed()
```

経過時間は`Duration`型と呼ばれる時間を表す構造体で表現されており，`as_secs`メソッドを呼び出すことで経過時間が秒で数値として得られます．

```rust
let duration_sec: u64 = duration.as_secs()
```

この処理を無限ループ`loop{...}`の内部で常に回しておき，
一秒経過するごとに経過時間と累積金額を出力しています．

```rust
println!("You have wasted {:.0} secs. = {:.3} Yen",count_second,second_wage* (count_second as f32) )
```

標準出力を担う`println!`マクロへは，第一引数にフォーマットを，第二引数以降にフォーマットの中の`{}`に当たる箇所に代入したい変数を渡します．
`{}`の内部に`{:.3}`などと書くと，小数点下三桁までにそろえて出力してくれたりします．


# 最後に
「この書き方は普通じゃない」「こんなエレガントな書き方があるよ」というアドバイスがありましたら，ぜひコメントや編集リクエストをお願いします．

次のことわざ: 「蛙の子は蛙」でクラスの作り方を勉強