🦀

WebプログラマがRustを触った所感

に公開

普段は主にPHPやTypeScriptを書いているんだけど、興味本位でRustを触ってみたので感想を残す。

公式のツールチェーンが充実している

普段TypeScriptを書くことが多いので、トランスパイルだのバンドルだの考えなくて済むのは良いなと思った。フォーマッタもリンタも rustup をインストールすれば入ってくれる。

rustlingsが良い

学習環境としてrustlingsがとても良かった。初心者でもセットアップに躓くことがなかったし、ゲーム感覚で楽しかった。広く浅くやる感じなので、全体感を掴みつつ、終わった後にどこを深めるかイメージしやすいのも良い。

型システムが独特なのと、今まで私がシステムプログラミングをあんまりやってこなかったので、

  • 標準ライブラリの知識
    • トレイト
    • デザインパターン(主に並行プログラミング関連)の実装
  • 非同期処理
  • マクロ

あたりはもうちょっと深めたいと思った。

後で教えてもらって知ったんだけど、日本語版があるらしい。
私は知らなかったので英語版をGoogle翻訳使いながら解いた。
sotanengel/rustlings-jp: Rustの練習問題(Rustlings)の日本語翻訳バージョンです。

Resultが優秀

Rustといえば静的型検査によるメモリ安全性の担保が注目されることが多い印象なんだけど、 Result型がすごく便利な印象を受けた。

特にquestion mark operatorが便利。

fn()?;

というのも、普段はTypeScriptを書いていると悩ましいのがエラー処理をどう設計するか。
よくあるパターンとしては下記のような感じ。

  • 例外を投げる
  • 結果を返り値として返す

前者はエラーを集約して一箇所で処理したい場合なんかによく使われる。
そもそもプロセスを落として良い場合とか、Webアプリケーションとかでエラー処理用のミドルウェアで処理する場合なんかが該当する。エラー処理の文脈とは少し外れるけど、大域脱出という性質を利用してちょっと変わった使われ方をすることもある。
Promiseをthrowするのはなぜ天才的デザインなのか #JavaScript - Qiita

後者はそうでない場合…場合によるけど、例えばHTTPクライアントで、異常系のレスポンスを表現するのには、例外を投げずにレスポンスオブジェクトを返すように設計されていることが多い気がする。ライブラリによっては異常系のステータスコードが返されると例外を投げることもあるけど。あとは EitherとかResultとか言われるものもこちらに該当する。

TypeScriptで「結果を返り値として返す」のパターンを使っていて、「エラーならXXする、それ以外ならOOする」を書きたいときにちょっと冗長に感じることがある。
例えばスキーマバリデーションの例を挙げるとこんな感じ。

  const v = someSchema.safeParse(obj);
  if (!v.success) {
    // バリデーションNG!
    return;
  }
  
  // バリデーションOK!
  return;

例外を使えばもうちょっと簡潔に書けるのだけど、これはこれでエラーがシグネーチャに現れない、というような問題点がある。

  const v = someSchema.parse(obj);
  // バリデーションOK!
  // (駄目なら例外が投げられる)
  return;

この点、Rustの Result型には優れた糖衣構文が用意されている。

  let r = some_fn()?;

  // もし some_fn がエラーを返せばそれが返される。この先は実行されない。
  process_result(r);
  return Ok();

簡潔に書けるのに加えて、エラーがシグネーチャに現れるというメリットもある。
map_errなど便利なメソッドが充実しているので、エラーや正常値を変換する処理を書きやすいのも良い。

感想

メモリ安全性のイメージが強かったんだけど、意外とそれ以外も好きなポイントが多く、雑に使ってもメリットを感じられそうだった。
Web系の開発言語を今すぐRustに乗り換えるかと言われるとそこまでではないけど、CLIツールとかを書く分には積極的に使っていきたいと思った。

Discussion