Rust勉強中 - その8 -> タプルとポインタ型

# 自己紹介
出田 守と申します。
しがないPythonプログラマです。
情報セキュリティに興味があり現在勉強中です。CTFやバグバウンティなどで腕を磨いています。主に低レイヤの技術が好きで、そっちばかり目が行きがちです。

Rustを勉強していくうえで、読んで学び、手を動かし、記録し、楽しく学んでいけたらと思います。

# 環境
新しい言語を学ぶということで、普段使わないWindowsとVimという新しい開発環境で行っています。
OS: Windows10 Home 64bit 1903
CPU: Intel Core i5-3470 @ 3.20GHz
Rust: 1.38.0
RAM: 8.00GB
Editor: Vim 8.1.1
Terminal: PowerShell

# 前回
前回はbool型とchar型について学びました。
[Rust勉強中 - その7](https://qiita.com/deta-mamoru/items/d28e0539958f331f1fb8)

# 型
## タプル
タプルは様々な型の要素を持つことができる型です。
### 例

|例|要素の型|
|---|---|
|("left", "right")|("&str", "&str")|
|(0, 1)|("i32", "i32")|
|('0', 1)|("char", "i32")|
|('0', "1", (2, '3'))|("char", "i32", "(i32, char)")|
|(0,)|("i32",)|

最後の例のようにカンマをタプルの末尾に追加しても良いです。また、**要素が一つだけのタプルを宣言する場合は、末尾にカンマを付けます。**これは、普通の括弧と区別するためです。

### ユニット型
たまに関数で値を何も返さないけども、何か返さないといけない場合、ユニット型が用いられています。

|ユニット型|
|---|
|()|

例えば以下のような感じです。

```Rust:main.rs
fn open_some_file(path: &str) -> std::io::Result<()> {
    let file = std::fs::File::open(path);
    ...
    Ok(())
}
```

### タプルのアクセス方法
タプルの要素へのアクセスにはちょっと癖があります。
タプルへのアクセスは必ず`t.数値`である必要があります。

|式|結果|
|---|---|
|t.0|成功|
|t.-1|エラー|
|t.i|エラー|
|t[i]|エラー|

ループなどで「i番目のタプル要素を参照」みたいなことはできないわけですね。注意が必要です。

また、タプルの中のタプル、例えば`(0, 1, 2, (3, 4))`の3にアクセスしたい場合、`(t.3).0`のようにアクセスします。

## ポインタ型
ポインタ型はメモリのアドレスを指します。
### 参照
参照型はどこかの値のメモリアドレスを指し、`&型`のように書きます(「&」を「レフ」と言う)。例えば、`&i32`と書けば、i32型の参照となります。また、変数xへの参照`&x`は、Rustでは「xへの参照を借用する」というようです。参照先の値を取り出すには`*x`とします。これを参照解決といいます。

参照には(不変？)参照と可変参照があります。前者は変更不可能な参照で、後者は変更可能な参照です。

|型|意味|
|---|---|
|&T|変更不可能な参照|
|&mut T|変更可能な参照|

```Rust
fn print_ref_examples() {
    println!("\n[print ref examples]");
    let mut x = 0;
    {
        println!("<immutable ref>");
        let y: &i32 = &x;
        println!("    &x = {} {:p}", &x, &x);
        println!("    y  = {} {:p}", *y, y);
    }
    {
        println!("<mutable ref>");
        let y: &mut i32 = &mut x;
        *y = 1;
        println!("    y = {} {:p}", *y, y);
    }
    println!("    x = {}", x);
}
```
```
[print ref examples]
<immutable ref>
    &x = 0 0x9beb7af514
    &y  = 0 0x9beb7af514
<mutable ref>
    &mut y = 1 0x9beb7af514
    x = 1
```

### Box
Box型は**ヒープメモリ上に値を確保**します。

ヒープにメモリを確保するには`Box::new`を使用します。

```Rust
fn print_box_example() {
    println!("\n[print box example]");
    let b1 = Box::new(0);
    let b2 = Box::new((0, '1', "2"));
    println!("b1 = {} {}", b1, get_type(&b1));
    println!("b2 = {:?} {}", b2, get_type(&b2));
}
```
```
[print box example]
b1 = 0 &alloc::boxed::Box<i32>
b2 = (0, '1', "2") &alloc::boxed::Box<(i32, char, &str)>
```

### rawポインタ
Rustには、`*const T`((不変)参照)と`*mut T`(可変参照)のrawポインタ型があります。これらはRustが管理しないポインタなので、安全ではありません。つまり、rawポインタ型が指す先はnullかもしれないし、初期化されていないアドレス領域かもしれないということです。rawポインタ型の参照解決は`unsafe`ブロック内で行う必要があります。
以下はunsafeブロック外で参照解決した場合エラーになりました。

```Rust
fn print_raw_example() {
    println!("\n[print raw example]");
    let b = Box::new(0);
    let unsafe_b: *mut i32 = Box::into_raw(b);
    println!("b = {:?} {}", *unsafe_b, get_type(&unsafe_b));
}
```
```
$ cargo run
   Compiling types v0.1.0 (C:\Users\deta\hack\rust\types)
error[E0133]: dereference of raw pointer is unsafe and requires unsafe function or block
   --> src\main.rs:245:29
    |
245 |     println!("b = {:?} {}", *unsafe_b, get_type(&unsafe_b));
    |                             ^^^^^^^^^ dereference of raw pointer
    |
    = note: raw pointers may be NULL, dangling or unaligned; they can violate aliasing rules and cause data races: all of these are undefined behavior

error: aborting due to previous error

```

最後に使用したソースです。

```Rust
...
fn print_tuple_examples() {
    println!("\n[print tuple examples]");
    println!("{:?} {:?}", ("left", "right"),    (get_type("left"), get_type("right")));
    println!("{:?} {:?}", (0, 1),               (get_type(0), get_type(1)));
    println!("{:?} {:?}", ('0', 1),             (get_type('0'), get_type(1)));
    println!("{:?} {:?}", ('0', "1", (2, '3')), (get_type('0'), get_type(1), get_type((2, '3'))));
    println!("{:?} {:?}", (0,),                 (get_type(0),));
}

fn print_unit_example() {
    fn open_some_file(path: &str) -> std::io::Result<()> {
        std::fs::File::open(path);
        Ok(())
    }
    println!("\n[print unit example]");
    println!("{:?} {:?}", (),                   (get_type(())));
    println!("open_some_file(\"secret.txt\")={:?}", open_some_file("secret.txt"));
}

fn print_tuple_access() {
    let t = (0, 1, 2, (3, 4));
    println!("\n[print tuple access]");
    println!("t = {:?}", t);
    println!("t.0 = {}", t.0);
    println!("(t.3).0 = {}", (t.3).0);
    // println!("t.3 = {}", t.3);
    // let i = 0;
    // println!("t.i = {}", t.i);
    // println!("t[i] = {}", t[i]);
}

fn print_ref_examples() {
    println!("\n[print ref examples]");
    let mut x = 0;
    {
        println!("<immutable ref>");
        let y: &i32 = &x;
        println!("    &x = {} {:p}", &x, &x);
        println!("    y  = {} {:p}", *y, y);
    }
    {
        println!("<mutable ref>");
        let y: &mut i32 = &mut x;
        *y = 1;
        println!("    y = {} {:p}", *y, y);
    }
    println!("    x = {}", x);
}

fn print_box_example() {
    println!("\n[print box example]");
    let b1 = Box::new(0);
    let b2 = Box::new((0, '1', "2"));
    println!("b1 = {} {}", b1, get_type(&b1));
    println!("b2 = {:?} {}", b2, get_type(&b2));
}

fn print_raw_example() {
    println!("\n[print raw example]");
    let b = Box::new(0);
    let unsafe_b: *mut i32 = Box::into_raw(b);
    unsafe {
        println!("b = {:?} {}", *unsafe_b, get_type(&unsafe_b));
    }
}

fn main() {
    ...
    println!(">> Tuple type <<");
    print_tuple_examples();
    print_unit_example();
    print_tuple_access();
    println!(">> Pointer type <<");
    print_ref_examples();
    print_box_example();
    print_raw_example();
}
```
```
$ cargo run
   Compiling types v0.1.0 (C:\Users\deta\hack\rust\types)
    Finished dev [unoptimized + debuginfo] target(s) in 0.76s
     Running `target\debug\types.exe`
>> Tuple type <<

[print tuple examples]
("left", "right") ("&str", "&str")
(0, 1) ("i32", "i32")
('0', 1) ("char", "i32")
('0', "1", (2, '3')) ("char", "i32", "(i32, char)")
(0,) ("i32",)

[print unit example]
() "()"
open_some_file("secret.txt")=Ok(())

[print tuple access]
t = (0, 1, 2, (3, 4))
t.0 = 0
(t.3).0 = 3
>> Pointer type <<

[print ref examples]
<immutable ref>
    &x = 0 0x56763ff954
    y  = 0 0x56763ff954
<mutable ref>
    y = 1 0x56763ff954
    x = 1

[print box example]
b1 = 0 &alloc::boxed::Box<i32>
b2 = (0, '1', "2") &alloc::boxed::Box<(i32, char, &str)>

[print raw example]
b = 0 &*mut i32
```

今回はここまで。