組込みエンジニアのためのRustのよくわからない記号まとめ

# はじめに

どうも、レガシー組込みエンジニアの@yagisawaです。
Rustを勉強しているとCでは見かけない言語仕様(主に記号の使い方)に出くわすことがあるので、チートシート的な感じでまとめてみました。
勉強が進み次第都度更新していく予定です。

:::note warn
「Rustでは`XXX`<ins>等に</ins>使います」と曖昧な表現をしていますが、私の勉強が足りていないだけで本記事で紹介しているもの以外の使い方も存在する可能性がある旨、予めご承知おきください。
:::

:::note warn
Cについても私が知らない使い方が存在する可能性がある旨、予めご承知おきください。仕事柄C89の仕様を主に扱っています。また本記事の主眼はRustであるため、Cの情報の充実度については本質ではありません。
:::

RustとCの記号の一覧は以下の記事を参考にしています。

https://doc.rust-jp.rs/book-ja/appendix-02-operators.html

https://programming-place.net/ppp/contents/c/appendix/sign.html

# 記号

## `!`

Cでは`論理否定` `非等価比較`等に使います。

```C:C
// 論理否定
flg = !flg;

// 非等価演算
if ( flg != false ) { ... }
```

Rustでは`論理否定` `非等価比較`の他、`ビット反転` `マクロ展開` `never型`等に使います。

### ビット反転

Rustのビット反転は`~`ではなく`!`です。
Cユーザがドハマりしそうなポイントで

```Rust:Rust
fn main() {
    let x: u32 = !0x55555555;
    println!("{:X}", x);
}
```

の結果は`0`ではなく`0xAAAAAAAA`になります。
`bool`型だと論理否定になるので、Cのように整数型とboot型を一緒くたに考えないように注意したいところです。

### マクロ展開

Rustのマクロはめちゃくちゃ難しいのでとりあえずCユーザに馴染みがありそうな例を。

```Rust:Rust
macro_rules! abs {
    ($e: expr) => (if $e < 0 {-$e} else {$e})
}

fn main() {
    let ret = abs!(-2);
    println!("{}", ret);
}
```

`abs`というお馴染み(？)のマクロを作ってみました。そのマクロを展開するには`abs!`と書きます。
お気付きかもしれませんが、Rustは標準出力処理もマクロです。

マクロの詳細を知りたい方は以下の記事をご参考ください(というか、これ見て私も勉強します…)。

https://keens.github.io/blog/2018/02/17/makurokurabu_rustshibu/

### never型

Rustでは関数の戻り値に値を何も返さない(つまり、決してreturnしない)ことを

```Rust:Rust
fn never_return() -> ! {
    loop {}
}

fn main() {
    never_return();
}
```

のように指定することができます。

## `:`

Cでは`三項演算子` `ラベル`等に使います。

```C:C
// 三項演算子
max = (val1 > val2) ? val1 : val2;

// ラベル
switch ( operator ) {
    case ADD: result = val1 + val2; break;
    case SUB: result = val1 - val2; break;
    case MUL: result = val1 * val2; break;
    case DIV: result = val1 / val2; break;
}
```

Rustでは`ラベル`の他、`型制約` `構造体フィールド初期化子`等に使います。
またRustの`ラベル`は`ループラベル`に限定されており、Cのように`goto`を使って好きなところにジャンプしたり等はできません。詳細は[ループラベル](#ループラベル)に記載します。
余談ですが、Rustに三項演算子はありません。

### 型制約

わかりやすい例だと変数宣言するときに使います。

```Rust:Rust
fn main() {
    let x: u32 = 1024;
    println!("{}", x);
}
```

ちなみにRustには型推論があるため、

```Rust:Rust
fn print_type_of<T>(_: T) {
    println!("{}", std::any::type_name::<T>())
}

fn main() {
    let x = 1024;
    print_type_of(x);
}
```

のように型を書かなくても変数宣言できます(私の実行環境では`i32`になりました)。

余談ですがRustは賢いので、

```Rust:Rust
fn main() {
    let x: u8 = 1024;
    println!("{}", x);
}
```

こんな事すると

```
error: literal out of range for `u8`
 --> Main.rs:2:17
  |
2 |     let x: u8 = 1024;
  |                 ^^^^
  |
  = note: `#[deny(overflowing_literals)]` on by default
  = note: the literal `1024` does not fit into the type `u8` whose range is `0..=255`

error: aborting due to previous error
```

エラーになります。

### 構造体フィールド初期化子

```Rust:Rust
struct Point {
    x: i32,
    y: i32
}

fn main() {
    let origin = Point {x: 0, y: 0};
    println!("x = {}, y = {}", origin.x, origin.y);
}
```

`origin`という`Point`型の変数を初期化するときこのように書きます。

## `;`

Cでは文の`終端子`ぐらいにしか使わないと思いますが、Rustでは`終端子`の他に`固定長配列記法`の一部に使われます。

### 固定長配列記法

```Rust:Rust
fn main() {
    let a1: [i32; 5] = [1, 2, 3, 4, 5];
    println!("{:?}", a1);
    
    let a2 = [100; 5];
    println!("{:?}", a2);
}
```

固定長配列の宣言及び初期化をするときこのように書きます。
`a1`は[型制約](#型制約)を使って配列の型とサイズを明示しています。
`a2`は全ての要素を100で初期化しています。`a2`の型は指定していませんが、右辺値より型とサイズが推論されています。

## `'`

Cでは`文字`ぐらいにしか使わないのではないでしょうか。

```C:C
char c = 'a';
```

Rustでは`文字`の他、`ループラベル` `名前付きのライフタイム`等に使います。

### ループラベル

Rustでは`for` `while` `loop`等のループを書くことができるのですが、それらに

```Rust:Rust
fn main() {
    let mut tbl = [[0; 3]; 3];
    tbl[1][2] = 10;

    'escape_label: for ary in tbl {
        for val in ary {
            println!("search!");
            if val != 0 { break 'escape_label; }
        }
    }
    
    println!("{:?}", tbl);
}
```

のようにラベルを付けることができます。そして`break`でラベルを指定することで多重ループを一気に抜け出すことができます。便利です。

### ライフタイム

Cユーザにはよくわからない概念だと思いますのでまずCの例を。

```C:C
#include <stdio.h>

int *max( int *val1, int *val2 ) {
    return (*val1 > *val2) ? val1 : val2;
}

int main( void ) {
    int x = 1;
    int *result;
    
    {
        int y = 10;
        result = max(&x, &y);
    }
    
    printf("%d\n", *result);
}
```

Cはこのプログラムを普通にビルドもできるし実行もできてしまいます。
出力結果はたまたま正しかったのですが、`max`内では(yの値の方が大きいため)`y`のポインタがreturnされ`result`に代入されるので、`printf`するとき`result`の参照先はスコープ外のはずです。試しに`printf("%d %d\n", *result, y);`としてみるとエラーになります。

Rustでも同じようなことをしてみると

```Rust:Rust
fn max( val1: &i32, val2: &i32 ) -> &i32 {
    return if *val1 > *val2 { val1 } else { val2 };
}

fn main() {
    let x = 1;
    let result;
    
    {
        let y = 10;
        result = max(&x, &y);
    }

    println!("{}", result);
}
```

```
error[E0106]: missing lifetime specifier
 --> Main.rs:1:37
  |
1 | fn max( val1: &i32, val2: &i32 ) -> &i32 {
  |               ----        ----      ^ expected named lifetime parameter
  |
  = help: this function's return type contains a borrowed value, but the signature does not say whether it is borrowed from `val1` or `val2`
help: consider introducing a named lifetime parameter
  |
1 | fn max<'a>( val1: &'a i32, val2: &'a i32 ) -> &'a i32 {
  |       ++++         ++             ++           ++

error: aborting due to previous error

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

「ライフタイム指定子の欠落」と言われエラーになります。
例にあるようにライフタイムパラメータを追加すると

```Rust:Rust
fn max<'a>( val1: &'a i32, val2: &'a i32 ) -> &'a i32 {
    return if *val1 > *val2 { val1 } else { val2 };
}

fn main() {
    let x = 1;
    let result;
    
    {
        let y = 10;
        result = max(&x, &y);
    }

    println!("{}", result);
}
```

```
error[E0597]: `y` does not live long enough
  --> Main.rs:11:26
   |
11 |         result = max(&x, &y);
   |                          ^^ borrowed value does not live long enough
12 |     }
   |     - `y` dropped here while still borrowed
13 | 
14 |     println!("{}", result);
   |                    ------ borrow later used here

error: aborting due to previous error

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

今度は「\`y\`は長生きできない」というエラーに変わりました。
全ての引数と戻り値に`'a`をつけましたが、これは「全ての引数と戻り値は同じライフタイム`'a`を持つ」という意味になります。そのため2つの引数のうち短い方のライフタイム(この例では`y`のライフタイム)が戻り値にも適用され、エラーとなったわけです。

補足ですがネット上の例ではライフタイムに大体`'a` `'b` `'static`辺りが使われていると思います。`'static`は「プログラムが実行されている限り有効な値への参照」つまり最大のライフタイムを表す特別な意味を持っていますが、それ以外についてはどんな名前でも問題ないようです。
つまり

```Rust:Rust
fn max<'shortest_lifetime>( val1: &'shortest_lifetime i32, val2: &'shortest_lifetime i32 ) -> &'shortest_lifetime i32 {
    return if *val1 > *val2 { val1 } else { val2 };
}
```

これでも大丈夫です。
流石に[キーワード](https://doc.rust-jp.rs/book-ja/appendix-01-keywords.html)はダメでしたが、`'i32`とかはいけました。


## `_`

Cでは変数・関数名等をスネークケースで書くときぐらいにしか使わないのではないでしょうか。

```C:C
int some_val = 123;
```

Rustでは`変数・関数名`等の他に、`「無視」パターン束縛` `整数リテラル`等に使います。

### 「無視」パターン束縛

色々なパターンがあるのですが

```Rust:Rust
fn main() {
    let x = 10;

    match x {
        0 => println!("x is 0."),
        1 => println!("x is 1."),
        _ => println!("x is other.")
    }
}
```

まず`match式`に使われます。`switch文`の`default`のような感じです。

```Rust
fn foo(_: i32) {
    println!("繰り返すだけ");
}

fn main() {
    let x = [1, 2, 3, 4, 5];

    for _ in x {
        foo(0);
    }
}
```

次にこんな感じでforや引数の値全体を無視することもできます。

```Rust:Rust
fn main() {
    let x         = 10;
    let warn      = 20;
    let _not_warn = 30;

    println!("{}", x);
}
```

それからRustは未使用変数に対してワーニングを出すのですが、変数名の先頭に`_`を付けていると未使用でもワーニングが出ません。

### 整数リテラル

```Rust:Rust
fn main() {
    let a      = 1_000_000;
    let b: u32 = 0x8000_FFFA;

    println!("{}, {:X}", a, b);
}
```

のように整数リテラルを`_`で区切って見やすくすることができます。

## `@`

Cではそもそも使わないと思いますが、Rustではパターン束縛に使います。

### パターン束縛

なんでこんな仕様にしたのか…私がスッキリしていないのでうまく説明できませんが。
まずこれを理解するためにはRustの`enum`と`match式`についてざっくり理解する必要があります。

Rustの`enum`は

```Rust:Rust
enum IpAddr {
    V4 { a1: u8,  a2: u8,  a3: u8,  a4: u8 },
    V6 { a: String }
}

let ip = IpAddr::V4 { a1: 192, a2: 168, a3: 0, a4: 1 };
```

のように列挙子にデータを持たせることができます。
そして

```Rust:Rust
fn main() {
    enum IpAddr {
        V4 { a1: u8,  a2: u8,  a3: u8,  a4: u8 },
        V6 { a: String }
    }
    
    let ip = IpAddr::V4 { a1: 192, a2: 168, a3: 0, a4: 1 };

    match ip {
        IpAddr::V4 { a1: 0..=127, a2, a3, a4 } => {
            println!("クラスAです")
        },
        IpAddr::V4 { a1: n @ 192..=223, a2, a3, a4 } => {
            println!("{}.{}.{}.{}はクラスCのV4アドレスです", n, a2, a3, a4)
        },
        IpAddr::V4 { a1, a2, a3, a4 } => {
            println!("{}.{}.{}.{}はV4アドレスです", a1, a2, a3, a4)
        },
        IpAddr::V6 { a } => {
            println!("{}はV6アドレスです", a)
        },
    }
}
```

のようにmatch式で`ip`がどのパターンにマッチするかによって処理を変えることができます。
このとき

```Rust:Rust
IpAddr::V6 { a } => {
    println!("{}はV6アドレスです", a)
},
```

のように書くと`IpAddr::V6`の中にあるデータをローカル変数`a`に代入し使用することができますが、中にあるデータに関係なく全ての`IpAddr::V6`がマッチします。
中にあるデータも考慮してマッチさせたいときは

```Rust:Rust
IpAddr::V4 { a1: 0..=127, a2, a3, a4 } => {
    println!("クラスAです")
},
```

のように`a1`の範囲書いてあげるのですが、`a1: 0..=127`の部分は「a1の範囲が0～127のもの」という意味だけで`a1`というローカル変数を宣言したことにはなっていません。後続の`a2` - `a4`はローカル変数として使用できるのですが…
そのため「a1の値も変数に代入して使いたいよ！」という場合は`@`を使って

```Rust:Rust
IpAddr::V4 { a1: n @ 192..=223, a2, a3, a4 } => {
    println!("{}.{}.{}.{}はクラスCのV4アドレスです", n, a2, a3, a4)
},
```

と書くようです。
ちなみにわかりやすいようにa1の値を`n`に代入しましたが、`a1: a1 @ 192..=223`と書いても大丈夫のようです。

## `|`

Cでは`論理OR` `ビットOR`等に使います。

```C:C
// 論理OR
if ( a || b ) { ... }

// ビットOR
a = b | c;
```

Rustでは`論理OR` `ビットOR`の他、`パターンOR` `クロージャ`等に使います。

### パターンOR

`match式`のパターンで

```Rust:Rust
fn main() {
    let x = 0;

    match x {
        0 | 1 => println!("x is 0 or 1."),
        _     => println!("x is other.")
    }
}
```

のように使います。

### クロージャ

モダンな言語の似たような仕様に`無名関数`や`ラムダ式`といったものがありますがCにはない仕様です。
[The Rust Programming Language](https://doc.rust-jp.rs/book-ja/ch13-01-closures.html)によると

> Rustのクロージャは、変数に保存したり、引数として他の関数に渡すことのできる匿名関数

だそうです。

例えばベクタをクロージャで指定したアルゴリズムでソートする`sort_by`という関数があり

```Rust:Rust
use std::cmp::Ordering;

fn main() {
    let mut v = vec![9, 5, 0, 7, 2, 1, 6, 4, 3, 8];

    // 昇順
    v.sort_by(|a, b| a.cmp(b));
    println!("{:?}", v);

    // 降順
    v.sort_by(|a, b| b.cmp(a));
    println!("{:?}", v);

    // 偶数のほうが小さい。偶奇が同じ場合は昇順
    v.sort_by(|a, b| match (a % 2).cmp(&(b % 2)) {
        Ordering::Less    => Ordering::Less,
        Ordering::Greater => Ordering::Greater,
        Ordering::Equal   => a.cmp(b)
    });
    println!("{:?}", v);
}
```

こんな感じで使います。

無理やり組込みっぽい例を出してみると、よくタイマーのコールバックとかで

```C:C
void foo( void )
{
    timer_start(500, cb_tmout);

    // なんか色々な処理
}

// 色々な関数があって
// 必ずしもコールバック関数を
// 近くに置ける訳では無い

void cb_tmout( void )
{
    led_blink();
}
```

こんなコードを書いて、「あれ、このタイマータイムアウトしたとき何するんだっけ？」みたいなことになることがある…と思いますが、クロージャを使うことで

```Rust:Rust
fn foo() {
    blink_timer.start(500, || led.blink());

    // なんか色々な処理
}
```

と書けるので、「あー、こいつタイムアウトしたらLEDブリンクするのね」とすぐにわかります。

## `?`

<font color="red">**TBD**</font>

## `#`

<font color="red">**TBD**</font>

## `$`

<font color="red">**TBD**</font>

## `()`

<font color="red">**TBD**</font>

## `<>`

<font color="red">**TBD**</font>

## `..`

<font color="red">**TBD**</font>

## `->`

<font color="red">**TBD**</font>

## `=>`

<font color="red">**TBD**</font>

## `...`

<font color="red">**TBD**</font>

# おわりに

何か新しい言語を学ぶときに未知の記号に戸惑うことがあります。記号ってなかなか検索でヒットさせるのが難しいですよね、名前もわからないですし。
この記事がそんなRust初学者の道標…は言い過ぎか、検索のきっかけぐらいにはなることを願います。