今年の言語はRust その４６

# 今年の言語はRust その４６

Rustを学びます

Rustの日本語ドキュメント 2nd Edition
https://doc.rust-jp.rs/book/second-edition/

オリジナル(英語)
https://doc.rust-lang.org/book/


## 実行環境

```sh
$ cargo -V
cargo 1.33.0 (f099fe94b 2019-02-12)

$ rustup -V
rustup 1.17.0 (069c88ed6 2019-03-05)

$ rustc --version
rustc 1.33.0 (2aa4c46cf 2019-02-28)

$  cat /proc/version
Linux version 4.14.97-74.72.amzn1.x86_64 (mockbuild@gobi-build-64002) 
(gcc version 7.2.1 20170915 (Red Hat 7.2.1-2) (GCC)) 
#1 SMP Tue Feb 5 20:59:30 UTC 2019

$ uname -a
Linux ip-10-100-0-8 4.14.97-74.72.amzn1.x86_64 
#1 SMP Tue Feb 5 20:59:30 UTC 2019 x86_64 x86_64 x86_64 GNU/Linux

$ cat /etc/\*release
NAME="Amazon Linux AMI"
VERSION="2018.03"
ID="amzn"
ID_LIKE="rhel fedora"
VERSION_ID="2018.03"
PRETTY_NAME="Amazon Linux AMI 2018.03"
ANSI_COLOR="0;33"
CPE_NAME="cpe:/o:amazon:linux:2018.03:ga"
HOME_URL="http://aws.amazon.com/amazon-linux-ami/"
Amazon Linux AMI release 2018.03

```

## 15 スマートポインタ

### 15.5 'RecCell<T>'と内部可変性パターン

#### 'RefCell<T>'で実行時に借用規則を強制する

まずは正常系
```rust
fn main() {
  let mut x = 5;
  let y = & x;
}
```

下記の場合はエラーです。

```rust
fn main() {
  let x = 5;
  let y = &mut x;
}
```

```bash
error[E0596]: cannot borrow immutable local variable `x` as mutable
(エラー: 不変なローカル変数`x`を可変で借用することはできません)
 --> src/main.rs:3:18
  |
2 |     let x = 5;
  |         - consider changing this to `mut x`
3 |     let y = &mut x;
  |                  ^ cannot borrow mutably

```

不変値があるときに、可変で借用はできないということです。


#### 内部可変性のユースケース:　モックオブジェクト

ユースケースを使って学びます

```rust
pub trait Messenger {
  fn send(&self, msg: &str);
}

pub struct LimitTracker<'a, T: 'a + Messenger> {
  messenger: &'a T,
  value: usize,
  max: usize,
}

impl<'a, T> LimitTracker<'a, T>
  where T: Messenger 
{

  pub fn new (messenger: &T, max: usize) -> LimitTracker<T> {
    LimitTracker {
      messenger,
      value: 0,
      max,
    }
  }

  pub fn set_value(&mut self, valuie: usize) {
    self.value = value;  

    let percentage_of_max = (self.value as f64) / (self.max as f64);

    if percentage_of_max >= 0.75 && percentage_of_max < 0.9 {
      self.messenger.send("Warnig: You've used up over 75% of your quota!");
    } else if percentage_of_max >= 0.9 && percentage_of_max < 1.0 {
      self.messenger.send("Urgent warning: You've used up over 90% ");
    } else if percentage_of_max >= 1.0 {
      self.messenger.send("Error: You are over your quota!");
    }


  }

}

```

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

  struct MockMessenger {
    sent_messages: Vec<String>, // 送信されたとする文字列の格納オブジェクト
  }

  impl MockMessenger {
    fn new() -> MockMessenger {
      MockMessenger {sent_messages: vec![] }
    }
  }

  impl Messenger for MockMessenger {
    fn send(&self, message: &str) {
      self.sent_messages.push(String::from(message));
    }
  }

  #[test]
  fn it_sends_an_over_75_percent_warning_message() {
    let mock_messenger = MockMessenger::new();
    let mut limit_tracker = LimitTracker::new(&mock_messenger, 100);

    limit_tracker.set_value(80);

    assert_eq!(mock_messenger.sent_messages.len(), 1);
  }
}
```

これだとコンパイルエラーが起きます

```rust
error[E0596]: cannot borrow immutable field `self.sent_messages` as mutable
(エラー: 不変なフィールド`self.sent_messages`を可変で借用できません)
  --> src/lib.rs:52:13
   |
51 |         fn send(&self, message: &str) {
   |                 ----- use `&mut self` here to make mutable
52 |             self.sent_messages.push(String::from(message));
   |             ^^^^^^^^^^^^^^^^^^ cannot mutably borrow immutable field

```

```rust
#[cfg(test)]
mod tests {
  use super::*;
  use std::cell::RefCell;

  struct MockMessenger {
    sent_messages: RefCell<Vec<String>>,
  }

  impl MockMessenger {
    fn new() -> MockMessenger {
      MockMessenger{ sent_messages: RefCell::new(vec![]) }
    }
  }

  impl Messenger for MockMessenger {
    fn send(&self, message: &str) {
      self.sent_messages.borrow_mut().push(String::from(message));
    }
  }

  #[test]
  fn it_sends_an_over_75_percent_warning_message(){
    assert_eq!(mock_messenger.sent_messages.borrow().len(), 1);
  }
}
```

だめだ！
分からない！
写経の限界がきた。

スマートポインタはSkipします。
2週目に重点的に学習します。


イエス！