Rust信者 vs Go信者、ガチで殴り合ってみた — 2026年バックエンド言語戦争の結論

$ |
Rust信者 vs Go信者、ガチで殴り合ってみた — 2026年バックエンド言語戦争の結論
$

バックエンド言語の選定は、プロジェクトの成功を左右する重要な判断だ。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年時点での現実解だと考えている。