[Rustのはじめ方] Part20: パッケージ・クレート・ライブラリ

はじめに

Rustでコードを書き進めていくと、「パッケージ」「クレート」「ライブラリ」といった言葉に出会います。これらはRustのプロジェクトを構成し、コードを整理・再利用するための重要な概念です。今回は、これらの関係性をしっかり理解していきましょう! 😊

これらの概念を理解することで、プロジェクトの構造を把握しやすくなり、他の人が作成した便利なコード(ライブラリ)を活用したり、自分自身で再利用可能なコードを作成したりできるようになります。

クレート (Crate) とは?

クレートは、Rustのコンパイルの最小単位です。Rustのコードは、まずクレートという単位でコンパイルされます。クレートには大きく分けて2つの種類があります。

バイナリクレート (Binary Crate) 🚀

実行可能なプログラム(例えばコマンドラインツールやアプリケーション)を生成するクレートです。プロジェクト内に src/main.rs ファイルがあると、それはバイナリクレートのルートファイルとして扱われます。このファイルにはプログラムのエントリーポイントである main 関数が含まれている必要があります。

// src/main.rs
fn main() {
    println!("Hello, world!");
}

ライブラリクレート (Library Crate) 📚

他のプログラムやクレートから利用されることを目的とした、再利用可能なコード(関数、構造体、モジュールなど)を提供するクレートです。プロジェクト内に src/lib.rs ファイルがあると、それはライブラリクレートのルートファイルとして扱われます。ライブラリクレートには main 関数は含まれません。

// src/lib.rs
pub fn add(left: usize, right: usize) -> usize {
    left + right
}

cargo new project_name コマンドで新しいプロジェクトを作成すると、デフォルトではバイナリクレートが作成されます(src/main.rs が生成される)。一方、cargo new --lib library_name のように --lib オプションを付けると、ライブラリクレートが作成されます(src/lib.rs が生成される)。

# バイナリクレートを持つパッケージを作成
cargo new my_app

# ライブラリクレートを持つパッケージを作成
cargo new --lib my_lib

パッケージ (Package) とは? 📦

パッケージは、1つ以上のクレートをまとめたものです。Cargo(Rustのビルドシステム兼パッケージマネージャ)は、このパッケージ単位でコードを管理・ビルド・テスト・公開します。すべてのRustプロジェクトは、基本的に1つのパッケージとして構成されます。

パッケージの中心となるのが Cargo.toml という設定ファイルです。このファイルには、パッケージの名前、バージョン、作者、依存する他のライブラリ(クレート)などの重要な情報が記述されています。

[package]
name = "my_package"
version = "0.1.0"
edition = "2021"

# See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html

[dependencies]
# ここに外部ライブラリ(クレート)への依存関係を記述します
# 例: rand = "0.8"

1つのパッケージは、以下のクレートを含むことができます。

  • 最大1つのライブラリクレート: パッケージ名と同じ名前のライブラリを提供します (src/lib.rs がルート)。
  • 任意の数のバイナリクレート: src/main.rssrc/bin/ ディレクトリ内の *.rs ファイルがそれぞれ独立したバイナリクレートになります。

例えば、あるパッケージがライブラリとしての機能を提供しつつ、そのライブラリを利用するコマンドラインツールも含みたい場合、src/lib.rssrc/main.rs の両方を持つことができます。

ライブラリ (Library) を活用しよう! 🛠️

ライブラリは、特定の機能を提供する再利用可能なコードの集まりです。Rustでは、ライブラリは主に「ライブラリクレート」として提供されます。ライブラリを使うことで、車輪の再発明を避け、効率的に開発を進めることができます。

Rustには、基本的なデータ型、マクロ、入出力操作、並行処理サポートなど、多くの便利な機能を提供する標準ライブラリ (std) が組み込まれています。特別な設定なしに、use std::...; のようにして利用できます。

use std::collections::HashMap;

fn main() {
    let mut map = HashMap::new();
    map.insert("key", "value");
    println!("{:?}", map);
}

外部ライブラリ (Crates.io) 🌐

Rustのエコシステムには、crates.io という公式のクレートレジストリがあります。ここには、世界中の開発者が作成した膨大な数の外部ライブラリ(クレート)が公開されており、誰でも自由に利用できます。

外部ライブラリを利用するには、まず Cargo.toml ファイルの [dependencies] セクションに使いたいライブラリ(クレート)の名前とバージョンを記述します。

[dependencies]
rand = "0.8"  # 例: 乱数生成ライブラリ rand のバージョン 0.8 を利用
serde = { version = "1.0", features = ["derive"] } # 例: シリアライズ/デシリアライズライブラリ serde の特定機能を利用

Cargo.toml に依存関係を記述した後、cargo buildcargo run を実行すると、Cargoが自動的に必要なライブラリをダウンロードし、コンパイルしてくれます。あとは、コード内で use キーワードを使ってライブラリの機能を利用するだけです。

// rand クレートを利用する例
use rand::Rng; // rand クレートの Rng トレイトをインポート

fn main() {
    let mut rng = rand::thread_rng();
    let n: u32 = rng.gen_range(1..=100); // 1から100までの乱数を生成
    println!("Random number: {}", n);
}

まとめ ✨

今回は、Rustのコード構成における重要な概念である「パッケージ」「クレート」「ライブラリ」について学びました。

概念 説明 主な要素
クレート (Crate) コンパイルの最小単位。バイナリまたはライブラリの形式がある。 src/main.rs (バイナリ), src/lib.rs (ライブラリ)
パッケージ (Package) 1つ以上のクレートをまとめたもの。Cargoが管理する単位。 Cargo.toml, 最大1つのライブラリクレート, 任意のバイナリクレート
ライブラリ (Library) 再利用可能なコードの集まり。Rustではライブラリクレートとして提供されることが多い。 標準ライブラリ (std), 外部ライブラリ (crates.io)

これらの関係性を理解することで、Rustプロジェクトの構造が明確になり、外部の便利なコードを活用したり、自身のコードを整理したりする際に役立ちます。特に crates.io のエコシステムはRustの大きな魅力の一つなので、ぜひ積極的に活用してみてください! 💪