Rustで書いたプログラムをデバッグする方法色々

## なぜRustをデバッグする方法を知るべきか
[Stackoverflowの2020年の調査](https://insights.stackoverflow.com/survey/2020#technology-most-loved-dreaded-and-wanted-languages-loved)によればRustは2020年時点でもっとも愛されている言語であり[C/C++並みの速度](https://benchmarksgame-team.pages.debian.net/benchmarksgame/fastest/rust-gcc.html)、あるいは[より速い速度](https://softwareengineering.stackexchange.com/questions/446992/how-can-rust-be-safer-and-faster-than-c-at-the-same-time)を持つのにメモリの安全性が保証されているとかコンパイラが賢いとか色々いい感じの言語です。でも、いい言語なのですが一般的に学習するのが難しいという評価がされています。そんなRustですが色々なデバッグ方法を知っていれば難易度はいくらか下がると思います。なのでここにデバッグ方法を色々まとめたいと思います。

といいつつ私もまだRustを始めたばかりで知らないことが多いのでなにか間違っていたらご指摘お願いします…。[Rust playground](https://play.rust-lang.org/)で実際にコードを試しながら読むとわかりやすいと思います！

## Printデバッグ
まずはおなじみのPrintデバッグです。println!("{:?}", 変数など);で中身を確認することができます。

```rust
pub fn main() {
    let test = vec![100, 101, 102, 103];
    println!("{:?}", test);
}
```
実行結果

```
[100, 101, 102, 103]
```

structに対して{:?}で情報をprintln!したい場合はdebugというattributeを追加しましょう。

```rust
pub fn main() {
    let test = Person { name: "test", age: 20 };
    println!("{:?}", test);
}

#[derive(Debug)] // これを追加
struct Person<'a> {
    name: &'a str,
    age: u8
}
```

実行結果

```
Person { name: "test", age: 20 }
```

enumも同じです。

```rust
pub fn main() {
    let test = Fruits::Apple("ringo".to_string());
    println!("{:?}", test);
}

#[derive(Debug)] // これを追加
enum Fruits {
    Apple(String),
    Grape(String),
    Orange(String)
}
```

実行結果

```
Apple("ringo")
```

## dbg!マクロ
Rust1.32.0からdbg!マクロが使用でき、その処理の含まれるファイル名・何行目の処理なのかを表示できます。

```rust
pub fn main() {
    let people = [
        Person { name: "test1", age: 20 },
        Person { name: "test2", age: 25 },
        Person { name: "test3", age: 30 },
    ];
    dbg!(&people);
}

#[derive(Debug)]
struct Person<'a> {
    name: &'a str,
    age: u8
}
```
実行結果

```
[src/main.rs:7] &people = [
    Person {
        name: "test1",
        age: 20,
    },
    Person {
        name: "test2",
        age: 25,
    },
    Person {
        name: "test3",
        age: 30,
    },
]
```

## デバッグビルド時にのみ情報をprintする
[stackoverflow](https://stackoverflow.com/questions/38141056/does-rust-have-a-debug-macro)の回答者がdebugビルド時にのみデバッグ情報をprintするマクロを回答してくれていました。以下stackoverflowからそのままコピペですが、debug!はreleaseビルド時にはデバッグの情報をprintしません。Playgroundで試す場合は[こちら](https://play.rust-lang.org/?version=stable&mode=debug&edition=2018&gist=2de72998b52d70177e40b45605544b6f)。

```rust
#[cfg(debug_assertions)]
macro_rules! debug {
    ($x:expr) => { dbg!($x) }
}

#[cfg(not(debug_assertions))]
macro_rules! debug {
    ($x:expr) => { std::convert::identity($x) }
}

fn main() {
    let x = 4;
    debug!(x);
    if debug!(x == 5) {
        println!("x == 5");
    } else {
        println!("x != 5");
    }
}
```

2020/11/8 追記
@benkiさんのコメントによると以下のような書き方でもデバッグビルド時のみデバッグ情報を表示することができるようです。情報提供ありがとうございます！！

```rust
if cfg!(debug_assertions) {
    dbg!(hoge);
}
```

## VSCodeでステップ実行
Rustはvscodeでステップ実行できます。以下、[情報元のstackoverflow](https://stackoverflow.com/questions/37586216/step-by-step-interactive-debugger-for-rust)からその方法をそのまま和訳します。
1.　VS Codeのインストール
2. 「Rust」もしくは「rust-analyzer」をVSCodeのExtensionsで検索してVSCodeに追加
3. 「CodeLLDB」をVSCodeのExtensionsで検索してVSCodeに追加
4. VSCodeの左のデバッグアイコンを押す→launch.jsonを追加を選択 すると「LLDB」がデバッグ対象の選択肢に追加されているのでこれを選びます。
5. LLDBを選択すると.vscodeフォルダのなかにデバッグ設定用のjsonファイルが追加されます。
6. このjsonファイルを（メモ帳でもなんでもいいので）開き、中身を以下のように書き換えます。

```json
{
    "version": "0.2.0",
    "configurations": [
        {
            "type": "lldb",
            "request": "launch",
            "name": "Rust Debug Launch",
            "program": "${workspaceRoot}/target/debug/${workspaceRootFolderName}",
            "args": [],
            "cwd": "${workspaceRoot}/target/debug/",
            "sourceLanguages": ["rust"]
        }
    ]
}
```

参考に[私のプロジェクト](https://github.com/lechatthecat/oran) ([Qiitaの記事](https://qiita.com/lechatthecat/items/cd421289be09acdf9714)) の場合、以下のような設定にしています。argsに実行時の引数を追加していますね。

```json
{
    "version": "0.2.0",
    "configurations": [
        {
            "name": "Rust Debug Launch",
            "type": "lldb",
            "request": "launch",
            "program": "${workspaceRoot}/target/debug/${workspaceRootFolderName}",
            "args": ["--file", "${workspaceRoot}/examples/test.orn"],
            "cwd": "${workspaceRoot}/target/debug/",
            "sourceLanguages": ["rust"]
        },
    ],
}
```

Cargo.tomlに以下を追加すると表示されるデバッグ情報がより正確になるかもしれません。
```
[profile.dev]
opt-level = 0
```

デバッグを開始するまえに、rustのコードはあらかじめbuildしておきます。
```sh
$ cargo build
```

あとはこんな感じでブレークポイントを設定して(行数が書いてあるところのちょっと左をクリックする)、デバッグメニューのところから「Rust Debug Launch」を選択、隣りにあるRunを押して実行すればブレークポイントで処理を止めることができます。
![Screenshot from 2020-11-08 01-55-18.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/260163/9c7f5658-801e-77e4-cc4c-3c0b6e63f22b.png)

hashmapの中身がちゃんと表示されない場合はこれも参考に
https://stackoverflow.com/questions/79298337/viewing-variable-values-in-visual-studio-code-using-rust-and-codelldb

2020/11/8 追記
有料らしいですが、CLionとIntellij idea ultimateもdebugできるそうです。
https://github.com/intellij-rust/intellij-rust
@_gz23_さん、情報の提供ありがとうございます！！