Rust By Exampleを勉強した記録: 2

筆者が、Rust By Exampleを写経したり、Activityを実行したりした記録の2記事目です

https://doc.rust-lang.org/rust-by-example/index.html

この記事のソースコード、記載は正しいかわかりませんし、効率的かどうかもわかりません
ご参考まで


# Enums

https://doc.rust-lang.org/rust-by-example/custom_types/enum.html


## ソースコード

<details><summary>ソースコード</summary>

```rust
enum WebEvent {
    PageLoad,
    PageUnLOad,
    KeyPress(char),
    Paste(String),
    Click { x: i64, y: i64 },
}

fn inspect(event: WebEvent) {
    match event {
        WebEvent::PageLoad => println!("page loaded"),
        WebEvent::PageUnLOad => println!("page unloaded"),
        WebEvent::KeyPress(c) => println!("pressed '{}'", c),
        WebEvent::Paste(s) => println!("pasted \"{}\"", s),
        WebEvent::Click { x, y } => println!("clicked at x={}, y={}", x, y),
    }
}

enum VeryVerboseEnumOfThingsToDoWIthNumbers {
    Add,
    Substruct,
}

type Operations = VeryVerboseEnumOfThingsToDoWIthNumbers;

impl Operations {
    fn run(&self, x: i32, y: i32) -> i32 {
        match self {
            Self::Add => x + y,
            Self::Substruct => x - y,
        }
    }
}

fn main() {
    let pressed = WebEvent::KeyPress('x');
    let pasted = WebEvent::Paste("my text".to_owned());
    let click = WebEvent::Click{ x: 20, y: 80 };
    let load = WebEvent::PageLoad;
    let unload = WebEvent::PageUnLOad;

    inspect(pressed);
    inspect(pasted);
    inspect(click);
    inspect(load);
    inspect(unload);

    let add = Operations::Add;
    let sub = Operations::Substruct;
    println!("Add result is {}", add.run(5,5));
    println!("Sub result is {}", sub.run(5,5));
}
```
</details>


## 出力結果
```
pressed 'x'
pasted "my text"
clicked at x=20, y=80
page loaded
page unloaded
Add result is 10
Sub result is 0
```

## Try

所有権の再確認

```diff
- let pasted = WebEvent::Paste("my text".to_owned());
+ let pasted = WebEvent::Paste("my text");
```

```
error[E0308]: mismatched types
  --> src\main.rs:37:34
   |
37 |     let pasted = WebEvent::Paste("my text");
   |                  --------------- ^^^^^^^^^- help: try using a conversion method: `.to_string()`
   |                  |               |
   |                  |               expected `String`, found `&str`
   |                  arguments to this enum variant are incorrect
   |
note: tuple variant defined here
  --> src\main.rs:5:5
   |
5  |     Paste(String),
   |     ^^^^^

For more information about this error, try `rustc --explain E0308`.
```

`to_owned`はそもそも何か？というと、

https://doc.rust-lang.org/std/borrow/trait.ToOwned.html

`std::borrow::ToOwned`トレイトのメソッドで、説明は以下の通り

> Creates owned data from borrowed data, usually by cloning.

`to_string`は、`std::string::ToString`トレイトのメソッドで、

https://doc.rust-lang.org/std/string/trait.ToString.html

> Converts the given value to a String

とのことです

この辺りの処理の使い分けや、似ている機能だけど、どういう意味の違いがあるかを調べていきたいですね


# use

https://doc.rust-lang.org/rust-by-example/custom_types/enum/enum_use.html


## ソースコード

<details><summary>ソースコード</summary>

```rust
enum Stage {
    Beginner,
    Advanced,
}

enum Role {
    Student,
    Teacher,
}

impl Stage {
    fn my_match(&self) {
        match self {
            Stage::Beginner => println!("Beginners are starting ther learning journey!"),
            Stage::Advanced => println!("Advanced learners are mastering their subjects!"),
        }
    }
}

impl Role {
    fn my_match(&self) {
        match self {
            Role::Student => println!("Students are acquiring knowledge!"),
            Role::Teacher => println!("Teachers are spreading knowledge!"),
        }
    }
}

fn main() {
    use crate::Role::*;
    use crate::Stage::{Advanced, Beginner};

    let stage = Beginner;
    let stage2 = Advanced;
    let role = Student;
    let role2 = Teacher;

    stage.my_match();
    stage2.my_match();

    role.my_match();
    role2.my_match();
}
```
</details>


## 出力結果
```
Beginners are starting ther learning journey!
Advanced learners are mastering their subjects!
Students are acquiring knowledge!
Teachers are spreading knowledge!
```

# C-like

https://doc.rust-lang.org/rust-by-example/custom_types/enum/c_like.html

列挙体はC言語っぽくも書ける

## ソースコード

<details><summary>ソースコード</summary>

```rust
enum Number {
    Zero,
    One,
    Two,
}

enum Color {
    Red = 0xff0000,
    Green = 0x00ff00,
    Blue = 0x0000ff,
}

fn main() {
    println!("zero is {}", Number::Zero as i32);
    println!("one is {}", Number::One as i32);
    println!("two is {}", Number::Two as i32);

    
    println!("roses are #{:06x}", Color::Red as i32);
    println!("violets are #{:06x}", Color::Blue as i32);
    println!("leafs are #{:06x}", Color::Green as i32);
}
```
</details>


## 出力結果
```
zero is 0
one is 1
two is 2
roses are #ff0000
violets are #0000ff
leafs are #00ff00
```

# Testcase: linked-list

https://doc.rust-lang.org/rust-by-example/custom_types/enum/testcase_linked_list.html


## ソースコード

<details><summary>ソースコード</summary>

```rust
use crate::List::*;

enum List {
    Cons(u32, Box<List>),
    Nil,
}

impl List {
    fn new() -> List {
        Nil
    }

    fn prepend(self, el: u32) -> List {
        Cons(el, Box::new(self))
    }

    fn len(&self) -> u32 {
        match *self {
            Cons(_, ref tail) => 1 + tail.len(),
            Nil => 0
        }
    }

    fn stringify(&self) -> String {
        match *self {
            Cons(head, ref tail) => {
                format!("{}, {}", head, tail.stringify())
            },
            Nil => format!("Nil"),
        }
    }
}

fn main() {
    let mut list = List::new();

    list = list.prepend(1);
    list = list.prepend(2);
    list = list.prepend(3);

    println!("linked list has length: {}", list.len());
    println!("{}", list.stringify());
}
```
</details>


## 出力結果
```
linked list has length: 3
3, 2, 1, Nil
```

## Try

Box<T>とはなんぞやと思って調べたところ、Rustではすべての値がデフォルトでスタックに割り当てられますが、
> Box<T>を作成することで、値を ボックス化 、すなわちヒープ上に割り当てることができます。ボックスとは正確にはヒープ上におかれたTの値へのスマートポインタです。ボックスがスコープを抜けると、デストラクタが呼ばれて内包するオブジェクトが破棄され、ヒープメモリが解放されます。

とのことです

https://doc.rust-jp.rs/rust-by-example-ja/std/box.html

スタックとかヒープとかは苦手なので、まだ理解できていないのですが、ポインタをスタックに積み、そのポインタが指す領域をヒープに配置するということかな？

ポインタをスタックに積むようにすることで、コンパイル時にメモリの大きさを決定できて、間接的に、ポインタが指す領域は実行時にメモリの大きさを決定できるようになる？

以下のページが包括的な情報です

https://doc.rust-jp.rs/book-ja/ch15-00-smart-pointers.html

https://doc.rust-jp.rs/book-ja/ch15-01-box.html

ここら辺は別途勉強したいと思います

# Enums

https://doc.rust-lang.org/rust-by-example/custom_types/enum.html


## ソースコード

<details><summary>ソースコード</summary>

```rust
static LANGUAGE: &str = "Rust";
const THRESHOLD: i32 = 10;

fn is_big(n: i32) -> bool {
    n > THRESHOLD
}

fn main() {
    let n = 16;

    println!("This is {}", LANGUAGE);
    println!("The threshold is {}", THRESHOLD);
    println!("{} is {}", n, if is_big(n) { "big" } else { "small" });

    //THRESHOLD = 5;
}
```
</details>


## 出力結果
```
This is Rust
The threshold is 10
16 is big
```

## Try

```diff
- //THRESHOLD = 5;
+ THRESHOLD = 5;
```

constantsな値は左辺に置けない仕様

```
error[E0070]: invalid left-hand side of assignment
  --> src\main.rs:15:15
   |
15 |     THRESHOLD = 5;
   |     --------- ^
   |     |
   |     cannot assign to this expression

For more information about this error, try `rustc --explain E0070`.
```

# 後書き

難しい要素も増えてきました
要勉強なところもあるため、別途勉強していきたいと思います