すでに知っていることと比較することで学ぶことができます。最近、トランジティブな依存関係のバージョン解決に関して、Rustがジャバと同じように動作すると思い込んで痛い目に遭いました。この投稿では、この2つを比較したいと思います。すでに知っていることと比較することで学ぶことができます。最近、トランジティブな依存関係のバージョン解決に関して、Rustがジャバと同じように動作すると思い込んで痛い目に遭いました。この投稿では、この2つを比較したいと思います。

Rust と Java における推移的依存関係バージョン解決の比較

すでに知っていることと比較することで学びます。最近、私はRustがJavaと同じように推移的依存関係のバージョン解決が機能すると思い込んで痛い目に遭いました。この記事では、両者を比較したいと思います。

依存関係、推移性、およびバージョン解決

各スタックの詳細に入る前に、この領域と関連する問題について説明しましょう。

\ Hello Worldレベルを超えるプロジェクトを開発する際、他の人が以前に直面した問題に遭遇する可能性が高いです。問題が広く存在する場合、誰かが親切で市民意識の高い人が、それを解決するコードをパッケージ化して他の人が再利用できるようにしている可能性が高いです。これで、そのパッケージを使用して、コア問題の解決に集中できます。これは今日の業界がほとんどのプロジェクトを構築する方法であり、他の問題をもたらすとしても:あなたは巨人の肩の上に立っています。

\ 言語にはプロジェクトにそのようなパッケージを追加できるビルドツールが付属しています。ほとんどの場合、プロジェクトに追加するパッケージを依存関係と呼びます。さらに、プロジェクトの依存関係には独自の依存関係がある場合があります:後者は推移的依存関係と呼ばれます。

Transitive dependencies

上の図では、CとDが推移的依存関係です。

\ 推移的依存関係には独自の問題があります。最大の問題は、推移的依存関係が異なるパスから要求されるが、異なるバージョンである場合です。下の図では、AとBの両方がCに依存していますが、異なるバージョンに依存しています。

ビルドツールはプロジェクトにどのバージョンのCを含めるべきでしょうか?JavaとRustでは異なる答えがあります。順番に説明しましょう。

Java推移的依存関係バージョン解決

注意:Javaコードはバイトコードにコンパイルされ、実行時に解釈されます(そして時にはネイティブコードにコンパイルされますが、これは現在の問題領域外です)。まず、実行時依存関係解決とビルド時依存関係解決について説明します。

\ 実行時には、Java仮想マシンはクラスパスの概念を提供します。クラスをロードする必要がある場合、ランタイムは設定されたクラスパスを順番に検索します。次のクラスを想像してください:

public static Main {     public static void main(String[] args) {         Class.forName("ch.frankel.Dep");     } } 

\ コンパイルして実行してみましょう:

java -cp ./foo.jar:./bar.jar Main 

\ 上記は最初にfoo.jar内でch.frankel.Depクラスを探します。見つかった場合、bar.jarにも存在する可能性があるかどうかに関係なく、そこで停止してクラスをロードします。見つからない場合は、bar.jarクラスでさらに検索します。それでも見つからない場合は、ClassNotFoundExceptionで失敗します。

\ Javaのランタイム依存関係解決メカニズムは順序付けられており、クラスごとの粒度を持っています。これは、上記のようにコマンドラインでクラスパスを定義してJavaクラスを実行する場合でも、マニフェストでクラスパスを定義するJARを実行する場合でも適用されます。

\ 上記のコードを次のように変更してみましょう:

public static Main {     public static void main(String[] args) {         var dep = new ch.frankel.Dep();     } } 

\ 新しいコードがDepを直接参照しているため、新しいコードはコンパイル時にクラス解決を必要とします。クラスパス解決は同じ方法で機能します:

javac -cp ./foo.jar:./bar.jar Main 

\ コンパイラはfoo.jar内でDepを探し、見つからない場合はbar.jarで探します。上記はJava学習の旅の始めに学ぶことです。

\ その後、作業単位はクラスではなく、JARとして知られるJava Archiveになります。JARは、バージョンを指定する内部マニフェストを持つ、美化されたZIPアーカイブです。

\ さて、あなたがfoo.jarのユーザーだとします。foo.jarの開発者はコンパイル時に特定のクラスパスを設定し、おそらく他のJARも含めています。自分のコマンドを実行するにはこの情報が必要です。ライブラリ開発者はこの知識をダウンストリームユーザーにどのように伝えるのでしょうか?

\ コミュニティはこの質問に答えるためにいくつかのアイデアを考え出しました:最初に定着した回答はMavenでした。Mavenにはプロジェクトオブジェクトモデルの概念があり、プロジェクトのメタデータと依存関係を設定します。Mavenは、推移的依存関係も自分の依存関係と共にPOMを公開するため、簡単に解決できます。したがって、Mavenは各依存関係の依存関係をリーフ依存関係まで追跡できます。

\ さて、問題文に戻りましょう:Mavenはバージョンの競合をどのように解決するのでしょうか?MavenはCに対してどの依存関係バージョンを解決するでしょうか、1.0または2.0?

\ ドキュメントは明確です:最も近いものです。

Dependency resolution with the same dependency in different versions

上の図では、v1へのパスの距離は2で、Bへ1つ、次にCへ1つです。一方、v2へのパスの距離は3で、Aへ1つ、次にDへ1つ、最後にCへ1つです。したがって、最短パスはv1を指します。

\ しかし、最初の図では、両方のCバージョンがルートアーティファクトから同じ距離にあります。ドキュメントは答えを提供していません。興味があれば、POMでのAとBの宣言順序に依存します!要約すると、Mavenはコンパイルクラスパスに含める重複した依存関係の単一バージョンを返します。

\ AがC v2.0で動作するか、BがC 1.0で動作する場合は素晴らしいです!そうでない場合は、おそらくAのバージョンをアップグレードするか、Bのバージョンをダウングレードして、解決されたCバージョンが両方で動作するようにする必要があります。これは痛みを伴う手動プロセスです—私がどのように知っているか聞いてください。さらに悪いことに、AとBの両方で動作するCバージョンがないことがわかるかもしれません。AまたはBを置き換える時間です。

Rust推移的依存関係バージョン解決

RustはJavaといくつかの点で異なりますが、私たちの議論のために最も関連性が高いのは次のとおりだと思います:

  • Rustはコンパイル時と実行時に同じ依存関係ツリーを持っています
  • すぐに使えるビルドツールCargoを提供しています
  • 依存関係はソースから解決されます

\ それらを一つずつ検討してみましょう。

\ Javaはバイトコードにコンパイルされ、その後それを実行します。コンパイル時と実行時の両方でクラスパスを設定する必要があります。特定のクラスパスでコンパイルし、異なるクラスパスで実行すると、エラーが発生する可能性があります。例えば、依存するクラスでコンパイルするが、そのクラスが実行時に存在しない場合を想像してください。または、存在するが互換性のないバージョンである場合。

\ このモジュラーアプローチとは対照的に、Rustはクレートのコードとすべての依存関係を一意のネイティブパッケージにコンパイルします。さらに、Rustは独自のビルドも提供するため、異なるツールの癖を覚える必要がありません。Mavenについて言及しましたが、他のビルドツールは上記のユースケースでバージョンを解決するための異なるルールを持っている可能性があります。

\ 最後に、Javaはバイナリ(JAR)から依存関係を解決します。対照的に、Rustはソースから依存関係を解決します。ビルド時に、Cargoは依存関係ツリー全体を解決し、必要なすべてのソースをダウンロードし、正しい順序でコンパイルします。

\ これを念頭に置いて、Rustは最初の問題でC依存関係のバージョンをどのように解決するのでしょうか?Javaのバックグラウンドから来た人には奇妙に思えるかもしれませんが、Rustは両方を含みます。実際、上の図では、RustはAをC v1.0でコンパイルし、BをC v2.0でコンパイルします。問題解決です。

結論

JVM言語、特にJavaは、コンパイル時クラスパスと実行時クラスパスの両方を提供します。これによりモジュール性と再利用性が可能になりますが、クラスパス解決に関する問題の扉を開きます。一方、Rustはライブラリであれ実行可能ファイルであれ、クレートを単一の自己完結型バイナリにビルドします。

\ さらに詳しく:

  • Maven - 依存関係メカニズムの紹介
  • Effective Rust - 項目25:依存関係グラフを管理する

2025年9月14日にA Java Geekで最初に公開

市場の機会
Brainedge ロゴ
Brainedge価格(LEARN)
$0.01143
$0.01143$0.01143
-0.95%
USD
Brainedge (LEARN) ライブ価格チャート
免責事項:このサイトに転載されている記事は、公開プラットフォームから引用されており、情報提供のみを目的としています。MEXCの見解を必ずしも反映するものではありません。すべての権利は原著者に帰属します。コンテンツが第三者の権利を侵害していると思われる場合は、削除を依頼するために [email protected] までご連絡ください。MEXCは、コンテンツの正確性、完全性、適時性について一切保証せず、提供された情報に基づいて行われたいかなる行動についても責任を負いません。本コンテンツは、財務、法律、その他の専門的なアドバイスを構成するものではなく、MEXCによる推奨または支持と見なされるべきではありません。

関連コンテンツ

BTC、ETH流出の中、XRPとSOL ETFが資金流入を集める

BTC、ETH流出の中、XRPとSOL ETFが資金流入を集める

現物XRPおよびSOL ETFが資金流入を獲得する一方、BTCとETHは資金流出に直面しており、市場のシフトを示唆しています。
共有
CoinLive2025/12/26 05:14
ビットコインは12月以来初めての利下げでFRBが金利を引き下げる中で安定

ビットコインは12月以来初めての利下げでFRBが金利を引き下げる中で安定

ビットコインは12月以来初めてのFRB(アメリカ合衆国連邦準備銀行)の利下げでも安定した動きを見せる、というポストがBitcoinEthereumNews.comに掲載されました。要約すると、連邦準備制度理事会は昨年12月以降、金利を据え置いていました。アメリカのドナルド・トランプ大統領は利下げを求めてFRBに圧力をかけ続けていました。暗号資産やその他の資産は通常、金融流動性を高める利下げから恩恵を受けます。アメリカの中央銀行は、広く予想されていた通り、水曜日に政策金利を0.25%引き下げました。これは経済が失速し、押し上げが必要だという最近の兆候の中で、そしてドナルド・トランプ大統領からの絶え間ない圧力の下での決定でした。ビットコインやその他の主要なデジタル資産は、直後にほぼ横ばいで取引されました。暗号資産市場データプロバイダーのCoinGeckoによると、時価総額で最大の暗号資産は最近116,000ドルをわずかに上回る水準で取引され、過去数時間で0.2%上昇しました。BTCは最近の数日間で上昇し、投資家はおそらく予想された決定を織り込んでいました。時価総額で2番目に大きい暗号資産であるイーサリアムは、同期間中4,501ドルで横ばいでした。FRBは労働省の報告書の下方修正後、金利を4%から4.25%の範囲に引き下げました。その報告書では、3月に終わる1年間で当初報告されていたよりも911,000人少ない雇用しか創出されておらず、その他の懸念すべき経済的兆候が示されていました。「経済見通しに関する不確実性は依然として高い」とFRBは声明で述べています。これらの懸念は、年率で2.9%に上昇し、銀行の長年の目標である2%を頑固に上回るインフレの脅威を上回りました。新たに就任したホワイトハウス任命のスティーブン・ミラン知事は、この決定に反対票を投じ、0.50%の利下げを支持しました。FRBはインフレを低く抑え、完全雇用を確保するという二重の使命を持っています。Decryptへのテレグラムメッセージで、「Crypto Is Macro Now」ニュースレターの著者であるノエル・アチソンは、大きな問題は予想された利下げではなく、FRB当局者からの更新された経済予測であり、中央銀行家たちが「...について一層神経質になっている」ことを示していると書いています。
共有
BitcoinEthereumNews2025/09/18 14:49
Trust Walletユーザーが謎のハッキング被害:数百人から600万ドル以上が盗まれる

Trust Walletユーザーが謎のハッキング被害:数百人から600万ドル以上が盗まれる

Trust Walletユーザーが謎のハッキング被害に:数百人から600万ドル以上が盗まれる という記事がBitcoinEthereumNews.comに掲載されました。大規模なハッキングに関する報告が
共有
BitcoinEthereumNews2025/12/26 06:35