パッケージとクレート

Beginner

This tutorial is from open-source community. Access the source code

はじめに

パッケージとクレートへようこそ。この実験は、Rust Bookの一部です。LabEx で Rust のスキルを練習することができます。

この実験では、パッケージとクレートについて学びます。クレートは、Rust コンパイラが考慮する最小のコード単位であり、バイナリクレートまたはライブラリクレートとなり得ます。パッケージは、1 つ以上のクレートのコレクションであり、1 セットの機能を提供します。

パッケージとクレート

これから扱うモジュールシステムの最初の部分は、パッケージとクレートです。

クレート は、Rust コンパイラが一度に考慮する最小限のコード量です。たとえ rustc を使って cargo を実行せず、単一のソースコードファイルを渡した場合でも(「Rust プログラムの記述と実行」で最初からやってきたように)、コンパイラはそのファイルを 1 つのクレートとして考えます。クレートにはモジュールを含めることができ、モジュールはクレートと一緒にコンパイルされる他のファイルに定義することができます。これについては、次のセクションで見ていきましょう。

クレートは 2 つの形式のいずれかになります。バイナリクレートまたはライブラリクレートです。バイナリクレート は、コマンドラインプログラムやサーバーなど、実行可能な実行ファイルにコンパイルできるプログラムです。それぞれには、実行可能ファイルが実行されたときに何が起こるかを定義する main という関数が必要です。これまでに作成したすべてのクレートはバイナリクレートでした。

ライブラリクレート には main 関数がなく、実行可能ファイルにコンパイルされません。代わりに、複数のプロジェクトで共有することを目的とした機能を定義します。たとえば、第 2 章で使った rand クレートは、乱数を生成する機能を提供します。ほとんどの場合、Rust コミュニティの人が「クレート」と言ったとき、彼らはライブラリクレートを指し、「クレート」を「ライブラリ」という一般的なプログラミング概念と交換可能に使っています。

クレートルート は、Rust コンパイラが開始するソースファイルであり、クレートのルートモジュールを構成します(「スコープとプライバシーを制御するためのモジュールの定義」でモジュールについて詳しく説明します)。

パッケージ は、1 セットの機能を提供する 1 つ以上のクレートの束です。パッケージには、それらのクレートをどのようにビルドするかを記述する Cargo.toml ファイルが含まれています。実際、Cargo は、コードをビルドするために使ってきたコマンドラインツール用のバイナリクレートを含むパッケージです。Cargo パッケージには、バイナリクレートが依存するライブラリクレートも含まれています。他のプロジェクトは、Cargo コマンドラインツールが使っている同じロジックを使うために、Cargo ライブラリクレートに依存することができます。

クレートは 2 つの形式のいずれかになります。バイナリクレートまたはライブラリクレートです。パッケージには好きなだけのバイナリクレートを含めることができますが、ライブラリクレートは最大で 1 つだけです。パッケージには、ライブラリまたはバイナリクレートのいずれかを少なくとも 1 つ含める必要があります。

パッケージを作成したときに何が起こるか見てみましょう。まず、cargo new my-project というコマンドを入力します。

$ cargo new my-project
     Created binary (application) `my-project` package
$ ls my-project
Cargo.toml
src
$ ls my-project/src
main.rs

cargo new my-project を実行した後、ls を使って Cargo が作成するものを見ます。プロジェクトディレクトリには、パッケージを与える Cargo.toml ファイルがあります。また、src ディレクトリがあり、その中に main.rs があります。Cargo.toml をテキストエディタで開き、src/main.rs が記載されていないことに注意してください。Cargo は、src/main.rs がパッケージと同じ名前のバイナリクレートのクレートルートであるという慣例に従っています。同様に、パッケージディレクトリに src/lib.rs がある場合、パッケージにはパッケージと同じ名前のライブラリクレートが含まれており、src/lib.rs がそのクレートルートです。Cargo は、クレートルートファイルを rustc に渡して、ライブラリまたはバイナリをビルドします。

ここでは、src/main.rs のみを含むパッケージがあり、これは my-project という名前のバイナリクレートのみを含んでいます。パッケージに src/main.rssrc/lib.rs がある場合、それには 2 つのクレートがあります。バイナリとライブラリの両方で、パッケージと同じ名前になります。パッケージは、src/bin ディレクトリにファイルを配置することで複数のバイナリクレートを持つことができます。それぞれのファイルが別個のバイナリクレートになります。

モジュールのチートシート

モジュールとパスの詳細に入る前に、ここでは、モジュール、パス、use キーワード、および pub キーワードがコンパイラでどのように機能するか、また、多くの開発者がコードをどのように整理しているかについてのクイックリファレンスを提供します。この章全体を通して、これらのルールのそれぞれの例を見ていきますが、モジュールがどのように機能するかを思い出すための便利な参照になります。

  • クレートルートから始める: クレートをコンパイルするとき、コンパイラは最初に、コンパイルするコードを探すために、クレートルートファイル(通常、ライブラリクレートの場合は src/lib.rs、バイナリクレートの場合は src/main.rs)を見ます。
  • モジュールの宣言: クレートルートファイルでは、新しいモジュールを宣言できます。たとえば、mod garden; というコードで「garden」モジュールを宣言すると、コンパイラはこれらの場所でモジュールのコードを探します。
  • インラインで、mod garden の後にあるセミコロンを置き換える波括弧の中
  • src/garden.rs ファイル内
  • src/garden/mod.rs ファイル内
  • サブモジュールの宣言: クレートルート以外の任意のファイルでは、サブモジュールを宣言できます。たとえば、src/garden.rsmod vegetables; と宣言することができます。コンパイラは、親モジュールの名前に基づくディレクトリ内で、サブモジュールのコードをこれらの場所で探します。
  • インラインで、mod vegetables の直後、セミコロンの代わりに波括弧の中
  • src/garden/vegetables.rs ファイル内
  • src/garden/vegetables/mod.rs ファイル内
  • モジュール内のコードへのパス: モジュールがクレートの一部になると、プライバシールールが許す限り、同じクレート内の他の場所からそのモジュール内のコードを参照できます。たとえば、庭の野菜モジュール内の Asparagus 型は、crate::garden::vegetables::Asparagus で見つけることができます。
  • プライベートとパブリック: モジュール内のコードは、既定で親モジュールから非公開になっています。モジュールを公開するには、mod の代わりに pub mod で宣言します。公開モジュール内の項目も公開するには、宣言の前に pub を使います。
  • use キーワード: 特定のスコープ内で、use キーワードは、長いパスの繰り返しを減らすために、項目へのショートカットを作成します。crate::garden::vegetables::Asparagus に参照できる任意のスコープ内で、use crate::garden::vegetables::Asparagus; というコードでショートカットを作成することができます。その後は、そのスコープ内でその型を使うために、Asparagus と書くだけで済みます。

ここでは、これらのルールを示す backyard という名前のバイナリクレートを作成します。クレートのディレクトリも backyard と名前が同じで、これらのファイルとディレクトリが含まれています。

backyard
├── Cargo.lock
├── Cargo.toml
└── src
├── garden
│ └── vegetables.rs
├── garden.rs
└── main.rs

この場合のクレートルートファイルは src/main.rs で、それには次のようなコードが含まれています。

use crate::garden::vegetables::Asparagus;

pub mod garden;

fn main() {
    let plant = Asparagus {};
    println!("I'm growing {:?}!", plant);
}

pub mod garden; の行は、コンパイラに対して、src/garden.rs にあるコードを含めるように指示します。それは次のようなコードです。

pub mod vegetables;

ここで、pub mod vegetables; は、src/garden/vegetables.rs のコードも含まれることを意味します。そのコードは次のようになっています。

#[derive(Debug)]
pub struct Asparagus {}

さて、これらのルールの詳細に入り、実際に動作させてみましょう!

まとめ

おめでとうございます!パッケージとクレートの実験を完了しました。LabEx でさらに多くの実験を行って、スキルを向上させることができます。