バックエンド言語の選定は、プロジェクトの成功を左右する重要な判断だ。2026年現在、注目を集めているのがRustとGoだ。どちらもモダンな言語であり、高パフォーマンスを実現できるが、その設計思想と得意分野は大きく異なる。本記事では、実務経験に基づいて両言語を徹底比較する。
パフォーマンス — Rustの圧倒的な強さ
ベンチマーク上、RustはGoを凌駕する場面が多い。Rustはゼロコスト抽象化を掲げ、C/C++に匹敵する実行速度を誇る。GC(ガベージコレクション)が存在しないため、予測可能なレイテンシを実現できる。
一方、Goも決して遅くない。Go 1.22で導入されたGCの改善により、テイルレイテンシは大幅に改善された。Webサーバーとしてのスループットは、多くの実用的なワークロードでRustに肉薄する。
// Rust — Axumでの高速APIサーバー
use axum::{routing::get, Router, Json};
use serde::Serialize;
#[derive(Serialize)]
struct User {
id: u64,
name: String,
email: String,
}
async fn get_users() -> Json<Vec<User>> {
let users = vec![
User {
id: 1,
name: "田中太郎".to_string(),
email: "tanaka@example.com".to_string(),
},
];
Json(users)
}
#[tokio::main]
async fn main() {
let app = Router::new().route("/users", get(get_users));
let listener = tokio::net::TcpListener::bind("0.0.0.0:3000")
.await
.unwrap();
axum::serve(listener, app).await.unwrap();
}
// Go — 標準ライブラリでのAPIサーバー
package main
import (
"encoding/json"
"net/http"
)
type User struct {
ID uint64 `json:"id"`
Name string `json:"name"`
Email string `json:"email"`
}
func getUsers(w http.ResponseWriter, r *http.Request) {
users := []User{
{ID: 1, Name: "田中太郎", Email: "tanaka@example.com"},
}
w.Header().Set("Content-Type", "application/json")
json.NewEncoder(w).Encode(users)
}
func main() {
http.HandleFunc("/users", getUsers)
http.ListenAndServe(":3000", nil)
}
学習コスト — Goの圧倒的な手軽さ
ここで大きな差が出るのが学習コストだ。Goは意図的に言語仕様をシンプルに保っている。キーワードは25個のみ。ジェネリクスが1.18で追加されたが、それでも言語仕様は驚くほどコンパクトだ。
Rustの学習曲線は急峻だ。所有権(Ownership)、借用(Borrowing)、ライフタイム(Lifetime)という独自の概念を理解するまでに、多くの開発者が数ヶ月を要する。しかし、これらの概念を理解すると、メモリ安全性が型システムによって保証される感動を味わえる。
Rustの所有権システム
// Rustの所有権 — コンパイル時にメモリ安全性を保証
fn main() {
let s1 = String::from("hello");
let s2 = s1; // s1の所有権がs2にムーブ
// println!("{}", s1); // コンパイルエラー!s1はもう使えない
println!("{}", s2); // OK
// 参照を使えば借用できる
let s3 = String::from("world");
let len = calculate_length(&s3);
println!("{} の長さは {}", s3, len); // s3はまだ使える
}
fn calculate_length(s: &String) -> usize {
s.len()
}
エコシステムとライブラリ
Goのエコシステムは実用主義的だ。標準ライブラリが充実しており、HTTPサーバー、JSON処理、暗号化、テストなど、多くの機能が標準で利用できる。外部依存を最小限に抑えたい場合、Goは最適だ。
Rustのエコシステムはcrates.ioを中心に急速に成長している。Webフレームワーク(Axum、Actix Web)、非同期ランタイム(Tokio)、ORM(Diesel、SeaORM)など、プロダクション品質のクレートが揃っている。ただし、Goほど「標準でなんでもできる」わけではない。
各分野の主要フレームワーク比較
- Webフレームワーク: Rust(Axum, Actix Web) vs Go(Gin, Echo, 標準net/http)
- ORM: Rust(Diesel, SeaORM) vs Go(GORM, Ent)
- gRPC: Rust(Tonic) vs Go(grpc-go)— Goが先行、Rustも追いついてきた
- CLIツール: Rust(Clap) vs Go(Cobra)— どちらも優秀
- WASM: Rustが圧倒的に有利。wasm-packで容易にコンパイル可能
並行処理モデル
GoのGoroutineは、並行処理を驚くほど簡単にする。Channelを使った通信モデルは直感的で、「Don't communicate by sharing memory; share memory by communicating」の哲学が貫かれている。
// Go — Goroutineで並行処理
func fetchAllAPIs(urls []string) []Response {
ch := make(chan Response, len(urls))
for _, url := range urls {
go func(u string) {
resp := fetchAPI(u)
ch <- resp
}(url)
}
var results []Response
for range urls {
results = append(results, <-ch)
}
return results
}
Rustの非同期処理はTokioランタイムが担う。async/await構文で記述するが、Pin、Future、Sendなどの概念が登場するため、Goに比べると複雑だ。しかし、その複雑さの裏にはゼロコスト抽象化がある。非同期処理のオーバーヘッドが最小限に抑えられるのだ。
コンパイル時間
Goのコンパイル速度は驚異的だ。大規模プロジェクトでも数秒でビルドが完了する。この速度は開発体験に直結する。コード変更→ビルド→テストのサイクルが高速に回る。
Rustのコンパイル時間は依然として課題だ。フルビルドに数分かかることも珍しくない。ただし、インクリメンタルビルドの改善やcraneliftバックエンドの導入により、開発中のビルド時間は年々改善されている。
デプロイとバイナリサイズ
どちらもシングルバイナリにコンパイルされるため、デプロイが容易だ。Dockerイメージの最小化にも適している。
GoのバイナリにはランタイムとGCが含まれるため、最小でも数MBになる。Rustのバイナリは極限まで小さくでき、組み込みシステムにも適用可能だ。
どちらを選ぶべきか — 判断基準
結論として、以下の基準で選定することを推奨する。
- チームの経験: Rustエンジニアが確保できるか。学習コストを許容できるか
- パフォーマンス要件: マイクロ秒単位のレイテンシが必要ならRust。ミリ秒単位で十分ならGo
- プロジェクト規模: マイクロサービスの一部ならGo、パフォーマンスクリティカルなコアサービスならRust
- 開発速度: プロトタイピングが重要ならGo。長期的なメンテナンス性を重視するならRust
- WASM連携: ブラウザ向けの高速処理が必要ならRust一択
「正しい言語選択とは、技術的な優劣ではなく、チームとプロジェクトの文脈に最適なものを選ぶことだ。」
我々のチームでは、APIゲートウェイとリアルタイム処理にRust(Axum + Tokio)を、CRUD系マイクロサービスにGo(Echo + GORM)を使い分けている。両方の強みを活かすハイブリッドアプローチが、2026年時点での現実解だと考えている。











>_ コメント