世界を動かす技術を、日本語で。

GoからRustへの移行

概要

  • GoからRustへの移行 は、速度や型の有無よりも 正しさ保証開発体験の違い が焦点
  • 本ガイドは バックエンド開発 に特化し、GoとRustの 実務的な比較 を提供
  • Goの強みと限界、Rust移行で得られるメリットを 具体例 とともに解説
  • ツールチェーンや型システム、エラーハンドリングなど 主要な違い を整理
  • Go開発者向け に、Rust導入の判断材料や 移行時の注意点 を明確化

GoからRustへの移行ガイド:バックエンド開発者のための実践比較

  • GoからRustへの移行 は、性能や型システムの単純な比較ではなく、 正しさ保証ランタイム特性開発者体験 が主な論点
  • 本ガイドは バックエンドサービス に焦点を当て、 Goの得意分野 (小さな静的バイナリ、ネットワーク中心の標準ライブラリ、HTTP/gRPC/DBエコシステム)と Rustの特徴 を比較
  • CLIツールや組み込み、ゲームエンジンには本ガイドの内容が完全には適用されない場合もある旨を注意喚起
  • 筆者は Goの設計思想に批判的 だが、Goの実用性や普及度を認め、客観的な比較を重視
  • Rustコンサルタント としての立場を明示しつつ、 両言語での実務経験 をもとに現場目線で解説

GoとRustのツールチェーン比較

  • Go は「バッテリー同梱」思想で、ビルド・テスト・フォーマット・依存管理などの 一貫したツールチェーン を提供
  • Rust も同様に cargo を中心とした豊富な標準ツールが特徴
    • go.mod / go.sum → Cargo.toml / Cargo.lock:プロジェクト管理
    • go build / go run → cargo build / cargo run:ビルド・実行
    • go test ./... → cargo test:テスト
    • go vet / golangci-lint → cargo clippy:静的解析
    • gofmt → cargo fmt:自動フォーマット
    • その他、ドキュメント生成や脆弱性スキャンも標準対応
  • Goはサードパーティツール (golangci-lint, mockgen等)への依存が多め、Rustは 公式ツールで網羅度が高い
  • コードスタイルの統一 (gofmt/rustfmt)は、議論の排除と生産性向上に寄与

GoとRustの主な違い

| 項目 | Go | Rust | |---------------------|---------------------------------------|----------------------------------------| | 安定版リリース | 2012 | 2015 | | 型システム | 静的・構造的・1.18以降ジェネリクス | 静的・名義的・ジェネリクス+トレイト+ライフタイム | | メモリ管理 | ガベージコレクション(低遅延) | 所有権・借用、GCなし | | Null安全 | nil多用 | nullなし、Option<T>で型安全 | | エラーハンドリング | errorインターフェース、if err != nil | Result<T, E>、?演算子、網羅的マッチ | | 並行処理 | goroutine+channel(CSP) | async/await、tokio、スレッド | | キャンセル | context.Context(慣習、型安全でない) | CancellationToken等、型安全 | | データ競合検出 | -race(実行時、確率的) | Send/Syncでコンパイル時に検出 | | コンパイル速度 | 非常に速い | 遅い(特にクリーンビルド) | | ランタイム | 約2MBのGoランタイム+GC | libcのみ、または完全静的リンク可能 | | バイナリサイズ | 小~中(数MB) | 同等、小型化オプションあり | | 学習曲線 | 緩やか | 急勾配 | | エコシステム規模 | 75万+モジュール | 25万+クレート |

  • 両言語とも単一バイナリ配布・強力な並行処理サポート が特徴
  • 違いは 型システムによる保証の範囲ランタイム制御の自由度

型システムによる保証の違い

  • Goは慣習やツール (go vet, errcheck, -race等)で安全性を担保
  • Rustは型システム (Option, Result, 所有権, Send/Sync等)で コンパイル時に強制
  • 例:Mutex<T>は型としてロック取得を強制し、ロック忘れのバグが発生しない設計

Go開発者がRustを検討する理由

  • 速度不足 ではなく、 エラーハンドリングの冗長さnilポインタによるセグフォ型システムの限界 (長らくジェネリクス未対応、enumやtraitの不在)への不満が主
  • 標準ライブラリの穴 (Set型未実装等)も不満点
nilによるパニックの事例
  • Goではnilチェック漏れによる 本番クラッシュ が発生しやすい
  • RustのOption<T>必ずNoneケースを考慮 させるため、カテゴリごとバグを撲滅可能
データ競合(Data Race)の検出
  • Goの-raceは 実行時検出 で、テストで発生しない競合は本番で露見
  • Rustは Send/Syncトレイトコンパイル時に共有可否を判定、競合は型エラーとして排除
エラーハンドリングの比較
  • Go:if err != nilによる 明示的・冗長なエラー処理、fmt.Errorfによるラッピングは慣習頼り
  • Rust:Result<T, E>と?演算子、#[from]属性で 自動的なエラー伝播・ラッピング、enumで網羅的なエラー型定義
  • 新たなエラー型追加時は全呼び出し箇所をコンパイラが指摘、見落としゼロ
ジェネリクスの違い
  • Goは1.18以降ジェネリクス対応だが、 制約や実装上の制限 あり
  • Rustは トレイト境界や型パラメータ を活用し、 より柔軟かつ型安全 な抽象化が可能

GoとRustのパターン対応・移行判断

  • Goの典型パターン (interface, goroutine, channel等)はRustでどう表現するかを順次学ぶ必要
  • 移行コスト は小さくないが、 安全性・保守性・型システムによる恩恵 が大きい分野ではRustが有力選択肢
  • 既存Goサービスの段階的移行併用運用 も可能

まとめ:どんな時にRustへ移行すべきか

  • Goのシンプルさ・生産性 が活きる領域ではGo継続が妥当
  • 正しさ保証・並行性・型安全性 が最重要な場合、 Rust移行は十分な価値
  • 両言語の長所短所を冷静に理解 し、 現場の要件に応じて選択判断 が必要

Hackerたちの意見

これ、ちょっとありきたりに聞こえるかもしれないけど、Rustの一番の不満はパッケージ管理の状況なんだよね。これは完全に開発者の考え方のせいだと思う。Rustのエルゴノミクスは好きなんだけど(データ型への関数的アプローチが美しいよね)、今、RustとGoで二つのプロジェクトを並行して進めてるんだ。依存関係のツリーが全然違ってて、Goのプロジェクトはほとんど標準ライブラリでカバーされてるのに、Rustのプロジェクトはrusqlite(sqlite)、clap(cli)、ratatui(tui)、tauri(gui)を要求してるのに、依存関係が400以上になっちゃってる。特にtauriが一番の問題なんだけど、これがなくても100近くになるのはマジでクレイジーだよ。もし、ちゃんとメンテされてるRustのクレートの代替品があれば、もっと気が楽になるんだけど。システムを壊さないようにしたいだけなんだよね。Rust-webの人たちは、Cargoをnpmみたいにしたがってるみたいだし。

面白いね。Goにはあまり詳しくないんだけど、Tauriに相当するものはGoの標準ライブラリにあるの?ユーザーケースに応じて、フロントエンドはGoで、バックエンドだけRustでやるのはアリかな?

標準ライブラリは、良いアイデアが消えていく場所だよね。それから httplib3、httplib4 が続く。つまり、私は Rust のアプローチが断然好き。標準ライブラリに依存するか他の依存関係に頼るかは、私にとってあまり重要じゃない。結局、依存関係なんだから。人々は、標準ライブラリだからって品質が良いとかメンテナンスが行き届いていると思いがちだけど、これは別の話。結局はリソース次第。確かに、標準ライブラリはリソースが多いかもしれないけど、肥大化してメンテナンスが難しくなることもあるしね…

必要な機能を正確に提供する他のパッケージをいくつもインポートするのが、必要な機能の一部しか提供しない大きな標準ライブラリを使うよりも悪い理由って何なの?

パッケージ管理はほぼすべての言語や技術の厄介な問題だよ。誰も「解決」してないし、これからも解決策は出てこないと思う(でも、何事も可能性はゼロじゃないよね?)。Go では、ライブラリの開発者がセマンティックバージョニングを正確に守ることに頼ってるし、バージョンを「固定」できないのが個人的に不満。いくつかの回避策はあるけど、SHA を使って疑似バージョンを提供したり、ベンダリング(既知の依存関係のキャッシュで、キャッシュ管理の問題もある)をしたりすること。週末に Python を仮想環境で使わなきゃいけなかった不運があったけど、うまくいかなかったし、Python から移行した理由を思い出させてくれた。Perl(cpan)、Java(maven, gradle)、Ruby(gems)、Go(dep, glide, vgo, modules)、Rust(cargo)、Node(npm, yarn など)、OS も Redhat(yum, rpm など)、Debian(apt)、Ubuntu(snap - なんでこれが必要なの??)などなど。

Rustのライブラリは多くのクレートから成り立っていて、それが依存関係グラフに影響を与えることに注意してね。これが実際よりも依存関係の数が多く見える原因なんだ。別々のクレートは同じメンテナーが管理していて、しばしば同じ上流のgitリポジトリに属しているからね。とはいえ、一般的な意見には同意するよ。Rustには、半ばメンテナンスが行き届いてない0.xバージョンのクレートもたくさんあって、代替手段がないことが多いから。

rusqlite(sqlite)、clap(cli)、ratatui(tui)、tauri(gui) これに匹敵する標準ライブラリを持つ言語って、Java以外にあるの?それに、Tauri自体が14のクレートで構成されていて、それぞれがビルドツリーに表示されることも忘れないでね。 https://github.com/tauri-apps/tauri/blob/dev/Cargo.toml そしてRatatuiは6つだよ: https://github.com/ratatui/ratatui/blob/main/Cargo.toml

ベンチマークをやる前はRustが好きだったけど、ほとんどのLLMがRustで書くのとGoで書くのの効果の差が、思ったより大きかったな(特にエージェント的なハーネスで、初期の環境問題を修正できるところ)。それを見てから、かなりのRustの伝道者になっちゃった。既存のコードベースから呼び出すバッチ処理ツールをRustで書くのは成功してるけど、まだフルプロダクションの移行には挑戦してない...。記事で指摘されてるGoの問題、特にnilの扱いについては、Codexでの徹底したコードレビューでどんどん解決されてきてると思う。最初から問題がないのが一番だけど、こういうセキュリティバグは、初期設計や実行にかけた努力と同じくらい、コードをレビューして理解する努力をする開発者にはオプションになりつつあるね。言語データは https://gertlabs.com/rankings?mode=agentic_coding

RustのLLMに対する弱点はコンパイル時間だね。LLMはコードを書くのが早いから、比較的コンパイルを待つ時間が人間よりも多くなる。だから、適度なサイズのプロジェクト(例えば、10万行以上)では、Rustのコンパイルが約10倍遅いことがボトルネックになってくる。重要なインフラを作るなら、そのコストを払うのは意味があるけど、内部サービスでインターネットに公開されていないものを書くなら、開発のスピードがもっと重要かもしれない。(遅いコンパイルが人間の開発速度にも影響すると思うけど、なぜか開発者はこれを定量化しようとすることがめったにないんだよね。)

詳細なコンパイラーエラーと強力な型システムのおかげで、変更 -> コンパイル -> 変更のループがエージェントにとって簡単に扱えるんだ。Rustはユーザーを強く制約するレールを提供してる。Codexはいつも何かをコンパイルさせることができるんだ。ただ、時にはイディオム的なアプローチが無理なときに失敗すべきだと思う…その代わりに、コンパイルできてリクエストを満たすような愚かな実装をすることがあるんだよね。

CやC++、PythonからRustに移行するのは色々な理由で理解できるけど、ウェブのバックエンド作業にはGoが合ってると思う。ほとんどRustで書いてるけど、最後にRustでウェブサーバー側のことをやったとき、Goを使っておけばよかったなって思った。OPがGoのエラー構文の冗長さを指摘してるけど、確かにいいポイントだね。Rustも最初は同じ問題があって、「?」構文を追加したんだ。これでエラーが出たときはエラー値を返すだけになる。Goのエラー処理はほとんどがそのまま書かれてる。Rustには統一されたエラータイプがないから、エラー処理が面倒なんだよね。Rustには三つの主要なエラーシステム(io::Error、thiserror、anyhow)があって、呼び出しのチェーンを通して渡すのが大変なんだ。(新しい言語には欠けてることが多くて、後から追加するのが面倒なことがある。ほぼ同じだけど互換性のないバージョンが出てくるから。定数型、ブール型、エラー型、多次元配列型、サイズ2、3、4のベクトルや行列型とその通常の操作。これらが早い段階で標準化されないと、プログラムは同じものの複数の表現に悩まされることになる。エラー処理を除けば、これらの問題はウェブ開発にはあまり影響しないけど、数値処理やグラフィックス、モデリングには大きな痛手だね。標準操作が数値の配列に適用されるから。)Goにはウェブサービスに対する二つの主な利点がある。まず、OPが指摘してるgoroutines。次に、OPがあまり言及してないライブラリ。Goにはウェブサービスに必要なほとんどのライブラリがあって、Googleが内部で使ってるものなんだ。だから、非常に使われている環境でも生き残ってる。マイナーなケースでもよく使われてる。これはRustのクレートには当てはまらなくて、成熟度が低くて、正式なQAサポートもないことが多い。

Rust には三つのエラーシステムはない。ひとつだけ、Error トレイトがある。io::Error はその実装の一つで、特別なものじゃない。thiserror で定義されたエラーもこれを実装してる。「Anyhow」は、関数が返すエラーの型を指定する API コントラクトを書くのが面倒なときに「何らかのエラー」と便利に言えるようにしてくれる。

Rust には統一されたエラー型がない Rust には実質的に一つのエラーがあって、それが Error トレイト。あなたが挙げたのはその使い方の一般的な例だけど、Box(基本的に anyhow::Error だね)だけでも全然問題ないよ。

同意する!最初の方で「バックエンドサービス向け」って言ってたのが気になった。Rust言語が大好きで、組み込みファームウェアやPCアプリに使ってるけど、ウェブバックエンドにはPythonを使ってるんだ。RustにはDjango(またはRails)に匹敵するツールセットがないからね。Flaskの類似品はあるけど、Flaskのエコシステムほど強力じゃないし。Goにはあまり経験がないけど、ウェブバックエンドにはRustよりGoを選ぶと思う。理由は同じくライブラリ(フレームワークを含む)エコシステムのためだよ。標準的な理由でAsync Rustのファンでもないしね(Rustのウェブエコシステムはほぼ完全にAsync必須だから)。

自分にとって、GoのRustに対する主な利点はコンパイル速度だね。それに比べると、Rustは多くのCやC++ライブラリに依存しているから、クロスコンパイルや再現可能なビルド、静的バイナリの生成が問題になることがあるんだ。Goのマイナス面は、GCがあまりにも単純すぎること。レイテンシスパイクが発生したときに、痛いリライト以外の対処法がほとんどないのが辛いよね。

しばらくGoの大ファンだったんだけど、最近SwiftやRustをプログラミングしてみて、ヌルポインタの参照を防ぐ保護がないコンパイラーや、並行性の安全性を保証しないコンパイラーはちょっと原始的に感じるようになったよ。でも、Goは標準ライブラリの面ではRustよりずっと良くやってたね。

thiserrorとanyhowは、ただのstd::errorにちょっと手間を加えたものだよ。io::errorは特定のstd::errorに過ぎないことに注意してね。Rustの全体のポイントは、Errorの実装を他のErrorの実装でラップしたり、matchを使って一つの実装を別の実装に変換したりすることなんだ。自分のエラータイプを十分に厳密に作れば、実際のバックトレースのオーバーヘッドなしで、ほぼ完全な意味的バックトレースが得られるから、これは他の多くの言語よりもずっと柔軟で検証可能だと思う。私はこのエラー処理を手伝うためにthiserrorをよく使うよ。特に、これがやることはDisplayとErrorを実装することだけだからね。特定の他のパラダイムではなく、基本的にコンパイルアウトされるマクロなんだ。anyhowは、型情報を捨てて文字列メッセージだけにすることができるから、他のパラダイムに最も近いかもしれないけど、それでもErrorsとよく統合されてる(そしてそれ自体がErrorsなんだ)。

バックエンドのウェブ開発には利点があるよね。Axumの型の使い方がすごく好きなんだ。例えば、こんな感じで書けるのがいいね:

pub async fn dataset_stats_handler(
    Path(dataset_id): Path,
    Query(verbose): Query,
) -> impl IntoResponse { ... }

ルートはこんな風に設定できて:

.route("/datasets/{dataset_id}/stats", get(dataset_stats_handler))

この「dataset_id」パス変数がそのままdataset_id引数にパースされて、クエリ文字列の「verbose」がブール値に変換されるのが超便利。Goと比べると、型の検証も一緒にできるしね。他にも良いところがたくさんあるよ。context.Contextがないこととか、ハンドラーがそのままレスポンスデータを返せることとか。あんまり好きじゃないのは、非同期処理かな。

面白いことに、全てのRustのソースコードはアセンブリの構文エラーに見える。

Goが大好きで、LLMベースじゃないものにはたくさん書いてたんだ。今はエージェント的なコーディングがあるから、すべてRustで書いてて、すごく満足してる。Rustを書くのは大変だったけど、Goは中堅エンジニア向けに簡単に書けるように作られてたからね。今はエージェント的なコーディングがあるから、Goの価値がどうなのか分からなくなってきた。私のRustサービスはパフォーマンスと信頼性の面で素晴らしいものになってるよ。

JVMやCLRのエコシステムからGoに移るのは、私にとってはダウングレードだね。言語設計はOberon(1987年)やLimbo(1995年)の文脈では意味があるけど、今はStandard MLやLispの遺産を基にした選択肢がたくさんあるのに、Goに妥協するのはダウングレードに感じる。1986年からコーディングしてるけど、ボイラープレートのエラーハンドリングや、定数値を宣言する唯一のメカニズムとしてコストが必要なら、選択肢はたくさんあったよ。

「あなたの組織が依存している、稼働率が高く、ビジネスにとって重要なサービス」って、RustのサービスがKubernetes上で動いてるとちょっと面白いよね。

グリーンフィールドなら、ぜひRustで書いてみて。ブラウンフィールドで、機能的に利益が出てるシステムがあるなら、元の言語で必要な部分だけを書き直して、そのまま続ければいいよ。知ってる言語と信頼できるチームで、少しずつ測れる方法でシステムを良くしていこう。他のことは無駄な宗教論争だよ。

チームが C#/Java/Go などでうまくやってるのに、Rust を使う理由が見当たらないな…

冗長さが主な問題なら、golang 1.28で大幅に削減される予定だよ: https://github.com/golang/go/issues/12854#issue-110104883

実際、これ素晴らしいね。リンクありがとう!

LLM の書き方の特徴はだんだん微妙になってきてるけど、特に「genuine」という言葉は目に飛び込んでくる。「ここが Go の真の強みで、なぜそう言えるのかを正確に言う価値がある」 「GC の停止がないのは本当に売りポイント」 「人間はメモリについての推論が本当に苦手」 「借用チェッカーが本当に厳しすぎる場合もある」 などなど。この記事が完全に AI 生成だとは思わないけど、AI に助けられたのは確か。もしそうなら、著者は本当に良い仕事をしたね!他の人はこのことについてコメントしてないから、内容にあまり影響を与えなかったんだろうね。ただ、これがどんどん一般的になってきて、見分けるのが難しくなってきてるのは変だな。

これは完全に話が逸れちゃったけど、「正確に言う価値がある」というのは、「genuine」という言葉の使い方よりもずっと強い AI 的な表現だね。

最近、LLMの文章が表面や特に基盤について話す傾向が異常に高いことに気づいたんだ。LLMが生成するテキストがクリシェで溢れているのは期待してるけど、みんながもう少し編集に気を使ってくれたら、同じ声を何度も読むことがなくなると思うんだよね。

この投稿は全部AI生成だと思う。著者はドラフトを入力して、いくつかの部分を編集したのかもしれない。例えばこの段落を見てみて:> Goは1.18でジェネリクスを手に入れたけど、実装には制約がある(型パラメータを持つメソッドがないとか、GCの形状スタンシルとか、時々驚くようなパフォーマンス特性がある)。Rustのジェネリクスはモノモーフィズされて、各インスタンスはゼロランタイムコストで特化したコードを生成する。トレイトと組み合わせることで、本当にゼロコストの抽象化が実現できる。どの文も意味があるし、重要で、ちゃんとした重みを持ってる。こういう書き方は、専門的な本や論文から期待するもので、ブログ投稿からは期待しないよね。それに、投稿を読むのが難しく(しかも退屈に)なる。

ここには同意するけど、理由はよくわからない。何がAI生成っぽいのか全然わからないんだ。「Goは多くの人にとって明らかに機能している」ってところまで行ったときに、AIアシストかもって疑い始めた(でも、もしかしたら間違ってるかもしれないし、AIアシストじゃないかもしれない。そういうのを見抜くのが苦手なんだ)。何かが「AIアシストっぽい」って感じると、記事自体が良くても興味を失っちゃう。もっと自分の考えを素直に書けるようになればいいのに。

記事を読んでいると、何度かLLMが生成した文章を読んでいる気がしたけど、全体的にはこの特定の記事は許容できるLLMの使い方の例だと思う。これを「AIのゴミ」って呼ぶつもりはないよ。正直言って、LLMのアシストを使って、テキストがLLM生成に見えないようにするのは本当に難しい。Gmailでメールを書くときに、テキストを良くするための提案が出てくるけど、それぞれは個別に見ると完璧に意味が通る。でも、いくつかをクリックすると、全体のメールがAIのゴミみたいに見えちゃうから、普通は変更を元に戻して、自分の不完全な手書きのバージョンに戻るんだ。

それに加えて、他にもいろいろあるよね。私もそう感じたし、彼がリンクした「とにかくGoを使え」っていう記事との対比がいいと思う。Goの記事はもっと人間的だよね。そういうのが好きで、LLM中心の文化よりも人間中心の言語や文化を選ぶと思う。やっぱり私はただの古い人間なんだな。

私はもうRustを使っていて、Goの経験はないから、この文章はあんまり自分には合わないかも。でも、一つだけ気になる点があるんだ。Rustでデータレースが「コンパイル時に捕まる」って言うのは、ちょっと誇張してる気がする。まるでRustがミューチュアルロックスタベーションや他の並行性の問題も扱えるみたいに聞こえるけど、実際はそうじゃないよね。「データレース」って技術的には正式な用語で、範囲も狭いけど、もうちょっと明確にしてほしいと思う。

これは変なドキュメントで、移行ガイドとRustのアドボカシー文書の両方を兼ねようとしてるね。結局、RustとGoの選択は「管理されたランタイムが欲しいかどうか」にほぼ集約されると思う。Rustプログラマーの世代は「管理されたランタイムは悪い」って自分たちに言い聞かせてるけど、それは明らかに間違い。管理されたランタイムが欲しいプログラミング領域の方が多いんだから。それが全てのケースでGoを選ぶ理由にはならないよ!Rustを好む主観的な理由はたくさんあるし、Goを書くときにmatchが恋しい(ただ、tokioやasync Rustは恋しくないけど)。どちらも問題の範囲を歪めずに使える正当な選択肢だよ(例えば、GoでLKMを書くのは変なことだと思う)。RustとGoの論争は、私たちの分野の変な後進的な部分だね。業界の大部分はPythonやNodeでシステムを作っていて、どの静的型付けコンパイル言語を使うかで議論してる変な人たちを見て笑ってる。Pythonと(Rust|Go)の対立は本当の問題だけど、RustとGoの対立はそうじゃない。

Nodeの私たちは、静的コンパイル型が欲しくてTypeScriptを取り入れたんだ。TSにもっとランタイムがあればいいのに。Pythonに関して唯一嫉妬してるのは、HTTPエンドポイントでJSONスキーマの強制がこんなにスムーズにできること。Zodの手間は、TSチームが教条的だからこそ存在するイライラの元だよ。

PureScript経由でNodeを使うのは大丈夫かも?でも一般的には、RustとGoの人たちは動的型付けの悪に対抗するために力を合わせるべきだと思う。タイプヒンティングは今やベストプラクティスと見なされてるんじゃない?それは実質的に欠陥を認めてるってことだと思う。良いヒンティングがあっても、推論よりは劣るし。推論を使えば、型が変わっても多くのコードをそのままにしておけるし、意図しない型変更からも守ってくれる。

LLMの使用がRustの利用を爆発的に増やしたね。自分でコードを書かずに、みんなが楽しんでると思うけど、そんな中で「よりパフォーマンスの良い言語」を選ばない理由は何だろう?(現実ではそうじゃないけど、一般的にはそう見られてるよね)。LLMがあなたのために色々なものを組み合わせてくれるとき、Goの管理されたランタイムはあまり価値がないよ。async Rustを書くときに、多少の粗さがあっても全く文句を言わないしね。

結局のところ、RustとGoの比較は「管理されたランタイムが欲しいかどうか」にほぼ完全に集約されるよね。Rustを使っていると、Goのランタイムの半分くらいはガベージコレクターが不要になるし。いくつかのクレートを追加すれば、Goのランタイムから得られるものの約95%を手に入れられるよ。Goは世界で最高のランタイムを持っている。そこは認めるけど、これが唯一の理由じゃないよね…

RustとGoの比較は「管理されたランタイムが欲しいかどうか」にほぼ完全に集約される。それはあんまり気にしてないかな。Goに対する不満は90%が言語自体の構文についてで、Rustと比べると型システムが弱いことだよ。管理されたランタイムについては、ほとんどのタスクでは、言語にそれがあるかどうかはあまり気にしてない。気にするタスクもあるけど、それは少数派だし、だからGoとRustを比較する際にはこの質問はほとんど関係ないと思ってる。GoとRustの議論がランタイムについてだとはあまり思えない。私の経験では、言語自体やそのエコシステム、コミュニティに関する主観的なことが多いと思う。 > RustとGoの対立は、私たちの分野の奇妙で気まずい後進的な部分だね。::shrug:: まあ、私はあんまり関わらずにRustを使ってて、幸せだし、ドラマを避けてる。少しGoを書いたこともあるけど、あんまり好きじゃなくて、次に進んだよ。

その通り。プログラマーの95%はアプリケーションプログラマーで、普通のユーザーが使うソフトウェアを出荷してる。ほとんどのケースで非GC言語を使うのは狂気だと思う。手動のメモリ管理は精神的に負担が大きくて、致命的なミスをするのも簡単だからね。そのメリットは、ゲームやトレーディングシステムを作っている場合を除いては、全く価値がないと思う。5%の人たちが他の95%のためにツールやインフラ層を書く場合は、そのメモリ管理のコントロールが必要かもしれないけど、本当に必要な場合を除いて、その複雑さに関わる意味が分からない。

簡単さとシンプルさを混同してるよね。Goの標準ライブラリには、こういう問題を抱えてるライブラリやパッケージがたくさんある。すごくタイトなインターフェースにすべてをまとめたがるんだよね(明らかな例としてはcrypto/*やhttpがある)。実装の詳細をユーザーに見せないようにしてる。これにはもちろん利点もあるけど、標準ライブラリの機能がちょっとでもニーズに合わないと、自分でゼロから(危険であったりパフォーマンスが劣るものを)書かなきゃいけなくなることもある。Rustは全体的には素晴らしいけど、いくつか変なところもある。例えば、lib.rsやmodはすごく直感的じゃなくて、過剰にデザインされていて不必要に複雑に感じた([彼らの本]を見てみて)。GoやJavaがライブラリやパッケージシステムにやったことが好きで、ああいう方がずっといいと思う。 [彼らの本]: https://doc.rust-lang.org/stable/book/ch07-05-separating-mod...

内部を隠すのが嫌になってきた。APIの安定性が保証されてないことが明確になる名前空間に入れて、必要なら使えるようにしておけばいいのに。君が言ってる通り、ちゃんと隠すのはただの苦痛で、得るものはない。ユーザーはバグを回避したり、機能を拡張したりするのが難しくなる。