Cargo vs Go Modules: 依存関係管理の比較
これらは 2 つの異なる言語に組み込まれた依存関係マネージャーです。Cargo (Rust) は SemVer 解決と Cargo.lock を用いた中央 registry を使い、Go modules は minimal version selection と go.sum を用いた分散型の URL ベースの import を使います。
1 つのプロジェクトで Cargo と Go modules のどちらかを選ぶわけではありませんが、両方を扱う際にはこれらを比較することでそれぞれのエコシステムが明確になります。両者は registry モデル、バージョン解決、そして CI でのキャッシュのされ方が異なります。以下が率直な比較です。
| Cargo (Rust) | Go modules | |
|---|---|---|
| Registry | crates.io (中央) | 分散型 (モジュール URL) + proxy |
| マニフェスト | Cargo.toml | go.mod |
| ロックファイル | Cargo.lock | go.sum (checksums) + go.mod のバージョン |
| 解決 | SemVer、互換性のあるアップグレードを許可 | Minimal version selection (MVS) |
| Vendoring | オプション | go mod vendor |
| Build cache | target/ + registry cache | GOMODCACHE + build cache |
解決の哲学
Cargo は constraints の範囲内で最新の SemVer 互換バージョンを解決し、正確なバージョンを Cargo.lock に記録します。Go は Minimal Version Selection を使います。すべての要件を満たす最も低いバージョンを選ぶため、別個のロックファイルなしでもビルドの再現性が非常に高くなります (go.sum は解決グラフではなく checksums を保存します)。どちらのアプローチが厳密に優れているわけではなく、新しさと決定性のトレードオフを異なる形で取っています。
Registry モデル
Cargo は crates.io に集約されるため、検索と公開が統一されています。Go の import はモジュールパス (多くの場合 VCS の URL) であり、これは分散型で単一の registry を避けますが、信頼性と完全性のために module proxy と checksum データベースに依存します。
CI では
どちらもキャッシュから大きな恩恵を受けます。Rust では ~/.cargo/registry、~/.cargo/git、target/ を Cargo.lock をキーにしてキャッシュします。Go では module cache と build cache を go.sum をキーにしてキャッシュします。特に Rust のコールドビルドは遅くなりがちなので、cache の再利用こそが CI 時間の短縮につながります。
結論
Cargo と Go modules は異なる言語で同じ問題を解決します。Cargo は中央 registry による SemVer の新しさを重視し、Go は minimal version selection と分散型モジュールによる再現性を重視します。CI では、各言語の cache を積極的にキャッシュすることが高速なビルドの鍵です。