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

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

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

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


# Testcase: List

https://doc.rust-lang.org/rust-by-example/hello/print/print_display/testcase_list.html

`?`をつけて、write!マクロ出力を継続させるということか？

```rust
write!(f, "{}", value)?;
```

## ソースコード

```rust
use std::fmt;

struct List(Vec<i32>);

impl fmt::Display for List {
    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
        let vec = &self.0;

        write!(f, "[")?;

        for (count, v) in vec.iter().enumerate() {
            if count != 0 { write!(f, ", ")?; }
            write!(f, "{}:{}", v,count)?;
        }

        write!(f, "]")
    }
}

fn main() {
    let v = List(vec![1, 2, 3]);
    println!("{}", v);
}
```

## 出力結果
```
[1:0, 2:1, 3:2]
```

## Try

いちばん最初の`write!`の`?`を削除すると、エラーとなる

```diff
- write!(f, "[")?;
+ write!(f, "[");
```

最初の`write!`で出力が終わってしまうことが原因かな？

```
   Compiling testcase_list v0.1.0 (E:\github\rust_example\testcase_list)
warning: unused `Result` that must be used
 --> src\main.rs:9:9
  |
9 |         write!(f, "[");
  |         ^^^^^^^^^^^^^^
  |
  = note: this `Result` may be an `Err` variant, which should be handled
  = note: `#[warn(unused_must_use)]` on by default
  = note: this warning originates in the macro `write` (in Nightly builds, run with -Z macro-backtrace for more info)
```

# Formatting

https://doc.rust-lang.org/rust-by-example/hello/print/fmt.html

各種Formattingの練習です
前述の`?`も併用しました

右寄せとか0詰めとかも、まだ書き方に慣れていないため、これは繰り返し練習する

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


```Rust
use std::fmt::{self, Formatter, Display};

#[derive(Debug)]
struct City {
    name: &'static str,
    lat: f32,   // Latitude
    lon: f32,   // Longitude
}

impl Display for City {
    fn fmt(&self, f: &mut Formatter) -> fmt::Result {
        let lat_c = if self.lat >= 0.0 { 'N' } else { 'S' };
        let lon_c = if self.lon >= 0.0 { 'E' } else { 'W' };

        write!(f, "{:>10}: {:.3}°{} {:.3}°{}",
            self.name, self.lat.abs(), lat_c, self.lon.abs(), lon_c)
    }
}

#[derive(Debug)]
struct Color {
    red: u8,
    green: u8,
    blue: u8,
}

impl Display for Color {
    fn fmt(&self, f: &mut Formatter) -> fmt::Result {
        write!(f, "RGB({:>3}, {:>3}, {:>3}) ", self.red, self.green, self.blue)?;
        write!(f, "0x")?;
        write!(f, "{:02x}", self.red)?;
        write!(f, "{:02x}", self.green)?;
        write!(f, "{:02x}", self.blue)
    }
}

fn main() {
    let cities = [
        City { name: "Dublin", lat: 53.347778, lon: -6.259722 },
        City { name: "Oslo", lat: 59.95, lon: 10.75 },
        City { name: "Vancouver", lat: 49.25, lon: -123.1 },
    ];

    for city in &cities {
        println!("{}", city);
    }

    for city in &cities {
        println!("{:?}", city);
    }

    let colors = [
        Color { red: 128, green: 255, blue: 90 },
        Color { red: 0, green: 3, blue: 254 },
        Color { red: 0, green: 0, blue: 0 },
    ];

    for color in &colors  {
        println!("{}", color);
    }

    for color in &colors  {
        println!("{:?}", color);
    }
}
```
</details>

## 出力結果

```text
    Dublin: 53.348°N 6.260°W
      Oslo: 59.950°N 10.750°E
 Vancouver: 49.250°N 123.100°W
City { name: "Dublin", lat: 53.34778, lon: -6.259722 }
City { name: "Oslo", lat: 59.95, lon: 10.75 }
City { name: "Vancouver", lat: 49.25, lon: -123.1 }
RGB(128, 255,  90) 0x80ff5a
RGB(  0,   3, 254) 0x0003fe
RGB(  0,   0,   0) 0x000000
Color { red: 128, green: 255, blue: 90 }
Color { red: 0, green: 3, blue: 254 }
Color { red: 0, green: 0, blue: 0 }
```

# Premitives

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

`primitives`: `基本データ型`
`type annotate`: `型指定`

integersのデフォルト型は`i32`、floatsは`f64`

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

```Rust
fn main() {
    let logical: bool = true;
    println!("{}", logical);

    let a_float: f64 = 1.0;
    let an_integer = 5i32;
    println!("{}", a_float);
    println!("{}", an_integer);

    let default_float = 3.0;
    let default_integer = 7;
    println!("{}", default_float);
    println!("{}", default_integer);

    let mut inferred_type = 12;
    println!("{}", inferred_type);
    inferred_type = 4294967296i64;
    println!("{}", inferred_type);

    let mut mutable = 12;
    println!("{}", mutable);
    mutable = 21;
    println!("{}", mutable);
    //mutable = true;

    let mutable = true;
    println!("{}", mutable);
}
```
</details>

## 出力結果

```
true
1
5
3
7
12
4294967296
12
21
true
```

# Literals and operators

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

## ソースコード

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

```rust
fn main() {
    println!("1 + 2 = {}", 1u32 + 2);
    //println!("1 - 2 = {}", 1u32 - 2);
    println!("1 - 2 = {}", 1i32 - 2);

    println!("1e4 is {}, -2.5e-3 is {}", 1e4, -2.5e-3);

    // 論理演算
    println!("true AND false is {}", true && false);
    println!("true OR false is {}", true || false);
    println!("NOT true is {}", !true);

    // Bit演算
    println!("0011 AND 0101 is {:04b}", 0b0011u32 & 0b0101);
    println!("0011 OR 0101 is {:04b}", 0b0011u32 | 0b0101);
    println!("0011 XOR 0101 is {:04b}", 0b0011u32 ^ 0b0101);
    println!("1 << 5 is {}", 1u32 << 5);
    println!("0x80 >> 2 is 0x{:x}", 0x80u32 >> 2);
    println!("0b{:08b} >> 2 is 0b{:08b}", 0x80u32, 0x80u32 >> 2);

    println!("One million is written as {}", 1_000_000u32);
}
```


</details>

## 出力結果

```
1 + 2 = 3
1 - 2 = -1
1e4 is 10000, -2.5e-3 is -0.0025
true AND false is false
true OR false is true
NOT true is false
0011 AND 0101 is 0001
0011 OR 0101 is 0111
0011 XOR 0101 is 0110
1 << 5 is 32
0x80 >> 2 is 0x20
0b10000000 >> 2 is 0b00100000
One million is written as 1000000
```

## Try
overflowを起こす計算のうち、あらかじめ判明しているものはエラーとなる

```diff
-    println!("1 - 2 = {}", 1i32 - 2);
+    println!("1 - 2 = {}", 1u32 - 2);
```

```
error: this arithmetic operation will overflow
 --> src\main.rs:3:28
  |
3 |     println!("1 - 2 = {}", 1u32 - 2);
  |                            ^^^^^^^^ attempt to compute `1_u32 - 2_u32`, which would overflow
  |
  = note: `#[deny(arithmetic_overflow)]` on by default
```




# Tuples

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

12個より要素が多いタプルはデバッグプリントできない
要素が1個のタプルをつくれるが、`,`が必要

## ソースコード

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

```rust
use std::fmt;

fn reverse(pair: (i32, bool)) -> (bool, i32) {
    let (int_parm, bool_parm) = pair;

    (bool_parm, int_parm)
}

fn transpose(matrix: Matrix) -> Matrix {
    Matrix(matrix.0, matrix.2, matrix.1, matrix.3)
}

#[derive(Debug)]
struct Matrix(f32, f32, f32, f32);

impl fmt::Display for Matrix {
    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
        writeln!(f, "( {} {} )", self.0, self.1)?;
        writeln!(f, "( {} {} )", self.2, self.3)
    }
}

fn main() {
    let long_tuple = (1u8, 2u16, 3u32, 4u64,
                    -1i8, -2i16, -3i32, -4i64,
                    0.1f32, 0.2f64,
                    'a', true);
    
    println!("Long tuple first value: {}", long_tuple.0);
    println!("Long tuple second value: {}", long_tuple.1);

    let tuple_of_tuples = ((1u8, 2u16, 2u32), (4u64, -1i8), -2i16);

    println!("tuple of tuples: {:?}", tuple_of_tuples);
    
    //let too_long_tuple = (1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13);
    //println!("Too long tuple: {:?}", too_long_tuple);

    let pair = (1, true);
    println!("Pair is {:?}", pair);

    println!("The reversed pair is {:?}", reverse(pair));

    println!("One element tuple: {:?}", (5u32,));
    println!("Just an integer: {:?}", (5u32));

    let tuple = (1, "hello", 4.5, true);
    let (a, b, c, d) = tuple;
    println!("{:?}, {:?}, {:?}, {:?}", a, b, c, d);

    let matrix = Matrix(1.1, 1.2, 2.1, 2.2);
    println!("{:?}", matrix);
    println!("{}", matrix);

    println!("Matrix:\n{}", matrix);
    println!("Transpose:\n{}", transpose(matrix));
}
```
</details>

## 出力結果
```
Long tuple first value: 1
Long tuple second value: 2
tuple of tuples: ((1, 2, 2), (4, -1), -2)
Pair is (1, true)
The reversed pair is (true, 1)
One element tuple: (5,)
Just an integer: 5
1, "hello", 4.5, true
Matrix(1.1, 1.2, 2.1, 2.2)
( 1.1 1.2 )
( 2.1 2.2 )

Matrix:
( 1.1 1.2 )
( 2.1 2.2 )

Transpose:
( 1.1 2.1 )
( 1.2 2.2 )
```


# Arrays and Slices

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

Arraysは同じ型のコレクションで、連続したメモリに配置される
arraysの長さはコンパイル時に既知、slicesの長さはコンパイル時に不定



## ソースコード

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

```rust
use std::mem;

fn analyze_slice(slice: &[i32]) {
    println!("First element of the slice: {}", slice[0]);
    println!("The slice has {} elements", slice.len());
}

fn main() {
    let xs: [i32; 5] = [1, 2, 3, 4, 5];
    let ys: [i32; 500] = [0; 500];

    println!("First element of the array: {}", xs[0]);
    println!("Second element of the array: {}", xs[1]);

    println!("Number of elements in array: {}", xs.len());

    println!("Array occupies {} bytes", mem::size_of_val(&xs));

    println!("Borrow the whole array as a slice.");
    analyze_slice(&xs);

    println!("Borrow a section of the array as a slice.");
    analyze_slice(&ys[1..4]);

    let empty_array: [u32; 0] = [];
    assert_eq!(&empty_array, &[]);
    assert_eq!(&empty_array, &[][..]);

    for i in 0..xs.len() + 1 { // Oops, one element too far!
        match xs.get(i) {
            Some(xval) => println!("{}: {}", i, xval),
            None => println!("Slow down! {} is too far!", i),
        }
    }
    
    //println!("{}", xs[5]); // compile error
    //println!("{}", xs[..][5]); // runtime error
}
```
</details>

## 出力結果
```
First element of the array: 1
Second element of the array: 2
Number of elements in array: 5
Array occupies 20 bytes
Borrow the whole array as a slice.
First element of the slice: 1
The slice has 5 elements
Borrow a section of the array as a slice.
First element of the slice: 0
The slice has 3 elements
0: 1
1: 2
2: 3
3: 4
4: 5
Slow down! 5 is too far!
```

## Try

コンパイルエラーになる場合

```rust
println!("{}", xs[5]); // compile error
```

```
   Compiling arrays_and_slices v0.1.0 (E:\github\rust_example\arrays_and_slices)
error: this operation will panic at runtime
  --> src\main.rs:36:20
   |
36 |     println!("{}", xs[5]); // compile error
   |                    ^^^^^ index out of bounds: the length is 5 but the index is 5   
   |
   = note: `#[deny(unconditional_panic)]` on by default

error: could not compile `arrays_and_slices` (bin "arrays_and_slices") due to 1 previous error
```

ランタイムエラーになる場合

```rust
println!("{}", xs[..][5]); // runtime error
```

```
thread 'main' panicked at src\main.rs:37:20:
index out of bounds: the len is 5 but the index is 5
note: run with `RUST_BACKTRACE=1` environment variable to display a backtrace
error: process didn't exit successfully: `target\debug\arrays_and_slices.exe` (exit code: 101)
```


# Structures

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

3つのタイプのStructuresがある
- タプル構造体、一般的にはタプル
- 古典的なC言語的な構造体
- ユニット、フィールドを持たない、ジェネリックスな使用用途

## ソースコード

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

```rust
#![allow(dead_code)]

use std::fmt;

#[derive(Debug)]
struct Person {
    name: String,
    age: u8,
}

struct Unit;

struct Pair(i32, f32);

struct Point {
    x: f32,
    y: f32,
}

struct Rectangle {
    top_left: Point,
    bottom_right: Point,
}

fn rect_area(rect: Rectangle) -> f32 {
    let Rectangle {
            top_left: Point {x: p1_x, y: p1_y },
            bottom_right: Point {x: p2_x, y: p2_y }
        } = rect;

    let height = if p1_y > p2_y {p1_y - p2_y} else {p2_y - p1_y};
    let width = if p1_x > p2_x {p1_x - p2_x} else {p2_x - p1_x};

    height * width
}

fn square(p: Point, f: f32) -> Rectangle {
    Rectangle {
        top_left: Point { x: p.x, y: p.y },
        bottom_right: Point { x: p.x + f, y: p.y + f }
    }
}

impl fmt::Display for Rectangle {
    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
        write!(f, "P1({}, {}), P2({}, {})",
            self.top_left.x,
            self.top_left.y,
            self.bottom_right.x,
            self.bottom_right.y,
        )
    }
}

fn main() {
    let name = String::from("Peter");
    let age = 25;
    let peter = Person { name, age };

    println!("{:?}", peter);

    let point: Point = Point { x: 10.0, y: 10.0 };
    let another_point: Point = Point { x: 15.0, y: 15.0 };

    println!("point coordinates: ({}, {})", point.x, point.y);

    let bottom_right = Point { x: 4.0, ..another_point };

    println!("second point: ({}, {})", bottom_right.x, bottom_right.y);

    let Point {x: left_edge, y: top_edge } = point;

    let rectangle = Rectangle {
        top_left: Point { x: left_edge, y: top_edge },
        bottom_right: bottom_right,
    };

    let _unit = Unit;

    let pair = Pair(1, 0.1);

    println!("pair contains {:?} and {:?}", pair.0, pair.1);

    let Pair(integer, decimal) = pair;

    println!("pair contains {:?} and {:?}", integer, decimal);

    println!("Rectangle is {}", rectangle);
    println!("Rectangle area is {}", rect_area(rectangle));

    let square_info = square(point, 10.0); 

    println!("Square is {}", square_info);
    println!("Square area is {}", rect_area(square_info));
}
```
</details>

## 出力結果
```
Person { name: "Peter", age: 25 }
point coordinates: (10, 10)
second point: (4, 15)
pair contains 1 and 0.1
pair contains 1 and 0.1
Rectangle is P1(10, 10), P2(4, 15)
Rectangle area is 30
Square is P1(10, 10), P2(20, 20)
Square area is 100
```

# 後書き

ディスプレイ用の処理の書き方がなかなか覚えられないため、要反復練習

型がきちきちに決まっていて、その通りにしか書けないため、コーディングしやすい印象でした