rust-analyzerを使ってみたら思いのほか素敵だったので紹介してみる

最近2冊目のRust本を購入し、少しずつRustの勉強を進めているのですがその際にrust-analyzerを入れてみたら思いのほか素敵だったのでそれの紹介です。

# rust-analyzerってなに？

Rustの入力補完や型チェック、文法ミスのチェックなどを行うための言語サーバープロトコル（Language Server Protocol、lsp）です。

以前まではRust公式とは関係無いプロジェクトでしたが、完成度が高かった影響なのか2022年2月ごろにRust公式になったようです。

> オープンソースのプログラミング言語であるRustの開発チームは、Rust用の言語サーバプロトコル（LSP）の新たな実装であるrust-analyzerプロジェクトが、Rustの一員として加わったことを、2月21日（現地時間）に発表した。

https://codezine.jp/article/detail/15610

以下のように紹介されていますが、確かにレビュー評価とかもかなり高くなっているようです。

> 　rust-analyzerは、Rustにとって非常に優れた言語サーバであるだけでなく、Visual Studio Codeの統計によればプログラミング言語全体でもっとも評価の高いLSP実装の1つであるという。

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/228778/7db571ce-6096-ddfb-b41c-6f9ff905c37d.png)

公式の発表 :

https://blog.rust-lang.org/2022/02/21/rust-analyzer-joins-rust-org.html

マーケットプレイスで見てみると、本記事執筆時点で約75万弱のダウンロードと165件のレビュー評価、4.9 / 5.0という評価の高さになっています。

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/228778/d570e0b7-c78d-886d-43b6-2d192d6d7c6e.png)

また、今まで使われていたRust公式のRust Language Serverのlspは2022年7月の発表＆9月の最後のリリースを持って廃止となります。今後は公式からもrust-analyzerを使ってね、ということになっています。

https://begi.net/news/archives/15438.html

https://blog.rust-lang.org/2022/07/01/RLS-deprecation.html

# rust-analyzerのVS Codeへのインストール

私の場合特に何も考えずにVS Codeの拡張機能をインストールすれば有効になりました（VS Codeの拡張機能関係の検索フォームでrust-analyzerと検索すれば出てくると思います）。

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/228778/b9d09693-bd6f-f6ac-763b-ab9e193c8bec.png)

ただ、最初に少し躓いたのですがVS Codeのワークスペースへのプロジェクトフォルダの追加がプロジェクトルートの位置になっていないケースではうまく動作してくれませんでした（下部のステータスバーでエラーが表示されていました）。

例えばCargo.tomlのファイルの位置が`your_project_folder/Cargo.toml`みたいになっていたら動きました。`your_project_folder/any_folder/Cargo.toml`みたいに間にフォルダが挟まれているとエラーになっています。そのため一度フォルダをワークスペースから取り除いて再度追加＆VS Codeの再起動を行っています（この辺はRustに慣れていないので、普通のRustではプロジェクトのルートをワークスペースに追加するのがRust界隈だと普通だったのかもしれません・・・）。

また、VS Code起動後に最初に諸々が有効になり終わるまではぼちぼち時間がかかっています（進捗は全てでは無いですがエディタ下部のステータスバーに表示されるようです）。

一度有効になってからは非常に快適でレスポンス良く動いてくれるので最初だけのんびり待っていましょう。

# rust-analyzerの一部機能紹介

以降の節で触っていて気付いた範囲で各機能を紹介していきます。

## 紹介用に使うものや設定

「Game Development with Rust and WebAssembly: Learn how to run Rust on the web while building a game」という最近発売されたRust + WASM + 2Dゲーム開発本を2冊目で進めており、そちらで使っているweb系のライブラリ（HTML Canvasなどの機能をRustから書けるようにするライブラリ）などをベースに触れていきます。

https://www.amazon.com/Game-Development-Rust-WebAssembly-building-ebook/dp/B09DDJ5JXF/

Cargo.tomlは以下のようにdependenciesを設定しています（一部抜粋）。

```toml:Cargo.toml
...

[dependencies]
wasm-bindgen = "0.2.78"
console_error_panic_hook = "0.1.7"

[dependencies.web-sys]
version = "0.3.55"
features = ["console", "Window", "Document", "HtmlCanvasElement", "CanvasRenderingContext2d", "Element"]

...
```

また、Rustは以下のバージョンを使っています。

```
$ rustc -V
rustc 1.61.0 (fe5b13d68 2022-05-18)
```

rust-analyzerのバージョンはv0.3.1131を使用しています。

エディタはVS Codeとなります。

## 関数やメソッド呼び出し時の引数名の表示

rust-analyzerで特徴的且つこれは良いアイデア・・・と思った機能に、関数やメソッドなどを呼び出した際に引数に指定した変数名が引数名とずれている際にエディタ上に引数名を表示してくれる機能があります。

例えば[シェルピンスキーのギャスケットのフラクタル](https://ja.wikipedia.org/wiki/%E3%82%B7%E3%82%A7%E3%83%AB%E3%83%94%E3%83%B3%E3%82%B9%E3%82%AD%E3%83%BC%E3%81%AE%E3%82%AE%E3%83%A3%E3%82%B9%E3%82%B1%E3%83%83%E3%83%88)を描画する`sierpinski`という関数があったとします。引数構造は以下のような形を想定します。

```rust
fn sierpinski(
        context: &web_sys::CanvasRenderingContext2d,
        points: [(f64, f64); 3],
        depth: u8) {
    ...
```

これを呼び出す際に以下のようなコードを書いたとします。

```rust
    ...
    sierpinski(
        &context,
        [(300.0, 0.0), (0.0, 600.0), (600.0, 600.0)],
        5);
```

するとrust-analyzerによってエディタ上で以下のように`points: `や`depth: `といった引数名が表示されます（表示されるだけで実際のコードには書かれておらず、コピペなどをしてもそれらは含まれません）。

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/228778/166e77ec-cde5-2883-d5a9-41c40b345a05.png)

まるでキーワード引数のように各引数がどの引数なのかが分かるようになります。

普段Pythonを書いているときなどはほぼキーワード引数ばかりを使っており、基本的にキーワード引数の方が好みです。この辺は以前記事にもしているため割愛します。

https://qiita.com/simonritchie/items/7d8382e821dd1e9bd98b

https://qiita.com/simonritchie/items/ada056671c34ea4f6a9b#%E5%9F%BA%E6%9C%AC%E7%9A%84%E3%81%AB%E3%82%AD%E3%83%BC%E3%83%AF%E3%83%BC%E3%83%89%E5%BC%95%E6%95%B0%E6%8C%87%E5%AE%9A%E3%81%A7%E7%B8%9B%E3%81%A3%E3%81%A6%E3%81%84%E3%82%8B%E7%AE%87%E6%89%80%E3%81%8C%E5%A4%9A%E3%81%84

一方でRustでは（この記事を書いている時点では恐らく）キーワード引数の機能はありません。少しこの点は以前Rustで気になっていたので、キーワード引数的に分かりやすくなるのは大変良いなと思います。この辺は検索していたらTwitterで同じような方がいらっしゃったので私以外にも気になっている方が少しはいらっしゃるかもしれません。

https://twitter.com/yhara/status/1398265176827174912?s=20&t=wtRbYDByDk7fGyYi1jjJnA

ちなみにですが引数名と変数名が一致しているときは表示されないようです。これは同じ名前が表示されても邪魔になるだけだよね・・・という感じなのかもしれません。
前出のサンプルコードでは第一引数の`context`引数に関しては引数名が表示されずにスキップされています。

## 型推論による型の表示

こちらもrust-analyzerで良いなと思った機能なのですが、型推論を使って変数などへの型の指定をスキップした際にも型を表示してくれます。
例えば以下のようなコードを書いたとします。返却される値の型は`Document`となります。

```rust
    ...
    let document = window.document().unwrap();
```

そうするとrust-analyzerが型推論結果をエディタ上で表示してくれます。`: Document`という表示がされていることが確認できます。

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/228778/c115a9d9-a86f-ebb3-7548-4db080dbdfaf.png)

※こちらもコピペなどしてもクリップボード上の結果には含まれません。あくまで表示のみとなっています。

型推論を使っている場合、マウスオーバーすれば型は確認できたりはしますがエディタ上に表示されていても快適なのでこれは良いなと思いました。型推論によるタイピングを減らしつつも通常のように型を明示した時と同じような可読性を得られます。

なお、メソッドチェーンを改行付きで使った場合各メソッドのタイミングの型も表示してくれます。この機能もメソッドチェーンの過程が分かりやすくてコードが読みやすくなりますし個人的にはRustにも慣れていないのでRustの勉強にもなります（「あー、過程では〇〇の型になっているのね・・・的に」）。

例えば以下のようなコードがあったとします。

```rust
    ...
    let context = canvas
        .get_context("2d")
        .unwrap()
        .unwrap()
        .dyn_into::<web_sys::CanvasRenderingContext2d>()
        .unwrap();
```

unwrapが複数ある理由やdyn_intoはキャストだよ、といった説明が書籍やライブラリのドキュメントに書かれていて理由は納得できても写経などの時は良くても自分で書くときは個数や順番などを間違えずにさくさくと書ける自信が無いぞ・・・と感じていました。

しかしrust-analyzerを使うとエディタ上では以下のような表示になります。メソッドチェーンの過程の型がすぐに確認できるので「なぜこの記述になっているのか」「各ステップでどんな型の変化になっているのか」などが一目で分かるようになります。

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/228778/6c723a2f-2f49-6c54-ddf8-fa65a7a92894.png)

## 使われていないuseの警告

※ここから先は他の言語でのlspやLintとかでも良くある機能となりますがrust-analyzerでもその機能あるよ、という紹介として一応触れておきます。

Pythonやjsで言うところのimport的なものになりますが、useの使われていないものを警告表示してくれます。コンパイル時などにも警告表示してくれたりはしますがエディタ上でも確認できるのは快適です。

たとえば`web_sys::console`というものを使っていなければ以下のように文字色が暗くなり下部に黄色の波線が付きます。

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/228778/c1135cb6-750c-9fea-36cf-e37602c47ec3.png)

マウスオーバーしてみるとunused importと表示され、使われていないimport（use）ということが分かります。

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/228778/1e8f8d26-ea5d-896b-d951-3a0ffb6c446f.png)

## シンタックスハイライト

rust-analyzerの最初の起動が終わった後は各種シンタックスハイライトが効きます。サードパーティーのcrate関係でも有効になっています。

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/228778/b03fba4c-1e6c-5604-8955-bd18ee2490fc.png)

## マウスオーバー時のドキュメンテーションコメントの表示

Pythonで言うところのdocstring、jsで言うところのJSDoc的なものになりますが、マウスオーバー時にRustのドキュメンテーションコメントを表示してくれます。

※ドキュメンテーションコメントに関しては以前記事を書いたのでそちらをご確認ください。

https://qiita.com/simonritchie/items/87d3743e138763ff3e85

crate、trait、関数、メソッドなどドキュメンテーションコメントが書かれているものは諸々確認できます。

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/228778/8ffbc00a-4f79-b432-f72f-2513483835b0.png)

## Go to Definition

右クリックしてGo to Definitionを選択したり、対象にカーソルが当たっている状態でF12キーを押したりすることで変数や関数、クラスなどの定義へと飛ぶことができます。

自身で定義したもの以外でも、サードパーティーのcrateとかでも飛ぶことができます。

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/228778/3ee8bf39-c8e8-8d45-e74a-6f12f919a974.png)

サードパーティーのものに飛んでみた例 :

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/228778/4c554151-22f8-bae7-2524-bda2363bb215.png)

## 関数やメソッド呼び出し時の引数情報の表示

この辺も良くある機能ではありますが、関数やメソッド呼び出し時に引数情報や引数の型、現在入力している引数位置の青色のハイライトなどをしてくれます。

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/228778/428ec5fa-5261-48b3-abed-09e950dbf66a.png)


# 参考サイト・参考文献

https://codezine.jp/article/detail/15610

https://marketplace.visualstudio.com/items?itemName=rust-lang.rust-analyzer

https://blog.rust-lang.org/2022/02/21/rust-analyzer-joins-rust-org.html

https://begi.net/news/archives/15438.html

https://blog.rust-lang.org/2022/07/01/RLS-deprecation.html

https://qiita.com/simonritchie/items/87d3743e138763ff3e85

https://ja.wikipedia.org/wiki/%E3%82%B7%E3%82%A7%E3%83%AB%E3%83%94%E3%83%B3%E3%82%B9%E3%82%AD%E3%83%BC%E3%81%AE%E3%82%AE%E3%83%A3%E3%82%B9%E3%82%B1%E3%83%83%E3%83%88