Closed8

The Rust Programming Language - Chapter 7 メモ

Tatsushi KiryuTatsushi Kiryu

https://doc.rust-jp.rs/book-ja/ch07-00-managing-growing-projects-with-packages-crates-and-modules.html

肥大化していくプロジェクトをパッケージ、クレート、モジュールを利用して管理する

  • パッケージ: クレートをビルドし、テストし、共有することができるCargoの機能
  • クレート: ライブラリか実行可能ファイルを生成する、木構造をしたモジュール群
  • モジュール と use: これを使うことで、パスの構成、スコープ、公開するか否かを決定できます
  • パス: 要素(例えば構造体や関数やモジュール)に名前をつける方法
Tatsushi KiryuTatsushi Kiryu

https://doc.rust-jp.rs/book-ja/ch07-01-packages-and-crates.html

パッケージとクレート

  • クレート
    • バイナリ or ライブラリのこと
    • crate root:Rust コンパイラの開始点かつ、クレートのルートモジュールを作るソースファイル
    • 関連した機能を1つのスコープにまとめることで、その機能が複数のプロジェクト間で共有しやすいようにする。名前の衝突を防ぐ
    • 元々の意味:ものを運ぶ木わくまたは竹かご
  • パッケージ
    • ある機能群を提供する1つ以上のクレート
    • Cargo.toml という、クレートをどのようにビルドするかを説明するファイルを持っている
    • パッケージは 0 or 1個のライブラリクレートを持っていないといけない(2個以上はダメ)

cargo new すると

  • Cargo.toml
  • src/main.rs

が生成される(パッケージが作られる)。Cargo.toml には src/main.ts への言及はないが、convention により src/main.rs が crate root として扱われる。

Tatsushi KiryuTatsushi Kiryu

https://doc.rust-jp.rs/book-ja/ch07-02-defining-modules-to-control-scope-and-privacy.html

モジュールを定義して、スコープとプライバシーを制御する

  • モジュール
    • クレート内のコードをグループ化し、可読性と再利用性を上げる。
    • 要素のプライバシーも制御できる。public / private
    • モジュールはネストできる
mod front_of_house {
    mod hosting {
        fn add_to_waitlist() {}
        fn seat_at_table() {}
    }
    mod serving {
        fn take_order() {}
        fn serve_order() {}
        fn take_payment() {}
    }
}
  • 暗黙的にルートには crate という名前のモジュールができる。
  • ディレクトリツリーのようなイメージ
crate
 └── front_of_house
     ├── hosting
     │   ├── add_to_waitlist
     │   └── seat_at_table
     └── serving
         ├── take_order
         ├── serve_order
         └── take_payment
Tatsushi KiryuTatsushi Kiryu

https://doc.rust-jp.rs/book-ja/ch07-03-paths-for-referring-to-an-item-in-the-module-tree.html

モジュールツリーの要素を示すためのパス

  • 絶対パス: crate を使うことで、クレートルートからスタートする

  • 相対パス: self, super あるいは今のモジュール内の識別子を使うことで、現在のモジュールからスタートする

  • 絶対パスも相対パスも、パス間はダブルコロン::で区切られる

  • モジュールのプライバシー境界

    • Rustは、内部実装の詳細を隠すことが標準。private by default
    • 同じモジュール内で定義されている兄弟
    • pub キーワードを使って要素を公開することができる。
    • プライバシールールは、モジュール、構造体、enum、関数、メソッドに適用される
// src/lib.rs
mod front_of_house {
    pub mod hosting {
        pub fn add_to_waitlist() {}
        fn seat_at_table() {}
    }
    mod serving {
        fn take_order() {}
        fn serve_order() {}
        fn take_payment() {}
    }
}

pub fn eat_at_reastaurant() {
    // 絶対パス
    crate::front_of_house::hosting::add_to_waitlist();
    // 相対パス
    front_of_house::hosting::add_to_waitlist();
}

↑でのポイントは、front_of_house は pub でないのに eat_at_reastaurant からはアクセスできること。これは front_of_houseeat_at_reastaurant が同じモジュール内で定義されているから。

相対パスをsuperで始める

// crate モジュールに属している
fn serve_order() {}

mod back_of_house {
    fn fix_incorrect_order() {
        cook_order();
        // crate::serve_order() と同義
        // back_of_house から見て crate が super にあたる
        super::serve_order();
    }
    fn cook_order() {}
}

構造体とenumを公開する

  • 構造体自体に pub キーワードつけてもフィールドは非公開のまま。
    • フィールド個別に pub をつけるつけないを決める。
    • 構造体はフィールドが公開されていなくても便利なことが多いので、pub がついていない限りは非公開のルールに従う。
    pub struct Breakfast {
        pub toast: String, // 公開される
        seasonal_fruit: String, // こちらは非公開のまま
    }
  • enum の場合は pub キーワードつけるとその variant は全て公開される。
    • enum は variant が公開されていないと不便。毎回全ての variant に pub つけるのは面倒なので、enum の variant はデフォルトで公開されるようになっている。
    pub enum Appetizer {
        Soup, // 公開される
        Salad, // 公開される
    }
Tatsushi KiryuTatsushi Kiryu

https://doc.rust-jp.rs/book-ja/ch07-04-bringing-paths-into-scope-with-the-use-keyword.html

useキーワードでパスをスコープに持ち込む

useキーワード(TypeScript の import のようなもの)

mod front_of_house {
    pub mod hosting {
        pub fn add_to_waitlist() {}
    }
}

// 絶対パス
use crate::front_of_house::hosting;
// 相対パス
// use self::front_of_house::hosting;

pub fn eat_at_restaurant() {
    hosting::add_to_waitlist();
}

慣例に従ったuseパスを作る

  • 関数の場合
    • どこで add_to_waitlist が定義されたのかが不明瞭なのでよくない。
    • 関数の定義されているモジュールまでに留めておくことで、関数がローカルで定義されていないことを明らかにできる。
mod front_of_house {
    pub mod hosting {
        pub fn add_to_waitlist() {}
    }
}

// Bad
use crate::front_of_house::hosting::add_to_waitlist;
pub fn eat_at_restaurant() {
    add_to_waitlist();
}

// Good
use crate::front_of_house::hosting;
pub fn eat_at_restaurant() {
    hosting::add_to_waitlist();
}
  • 構造体や enum の場合
    • フルパスを指定するのが慣例的。
    • はっきりした理由はなく、自然発生した慣習で、みんなこのやり方で慣れているというだけ。
// Bad
use std::collections;
fn main() {
    let mut map = collections::HashMap::new();
    map.insert(1, 2);
}

// Good
use std::collections::HashMap;
fn main() {
    let mut map = HashMap::new();
    map.insert(1, 2);
}
  • 名前が衝突してしまう場合は、モジュールまでに留めておく
use std::fmt;
use std::io;

fn function1() -> fmt::Result {
    // --snip--
    // (略)
}

fn function2() -> io::Result<()> {
    // --snip--
    // (略)
}

新しい名前をasキーワードで与える

as キーワードでリネームできる。(TypeScript の as のようなもの)

use std::fmt::Result;
use std::io::Result as IoResult;

fn function1() -> Result {
    // --snip--
}

fn function2() -> IoResult<()> {
    // --snip--
}

pub useを使って名前を再公開する

pub use で再公開する(TypeScript の re-export のようなもの)

mod front_of_house {
    pub mod hosting {
        pub fn add_to_waitlist() {}
    }
}

// re-export
pub use crate::front_of_house::hosting;

pub fn eat_at_restaurant() {
    hosting::add_to_waitlist();
}

外部のパッケージを使う

外部パッケージも Cargo.toml に追加しさえすれば、use キーワードを使って同様に使うことができるようになる。

巨大なuseのリストをネストしたパスを使って整理する

use std::cmp::Ordering;
use std::io;
// ↓
use std::{cmp::Ordering, io};

self を使った方法

use std::io;
use std::io::Write;use std::io{self, Write};

glob演算子

wildcard 指定できる

use std::collections::*;
Tatsushi KiryuTatsushi Kiryu

https://doc.rust-jp.rs/book-ja/ch07-05-separating-modules-into-different-files.html

モジュールを複数のファイルに分割する

// src/lib.rs

// mod front_of_houseの後にブロックではなくセミコロンを使うと、Rustにモジュールの中身を`モジュールと同じ名前をした別のファイル`から読み込むように命令します。
// これは覚えておかないと
mod front_of_house;

pub use crate::front_of_house::hosting;

pub fn eat_at_restaurant() {
    hosting::add_to_waitlist();
}

以下のファイルの中身が src/lib.rs に展開される

// src/front_of_house.rs
pub mod hosting {
    pub fn add_to_waitlist() {}
}
Tatsushi KiryuTatsushi Kiryu

https://doc.rust-jp.rs/book-ja/ch07-05-separating-modules-into-different-files.html

モジュールを複数のファイルに分割する

// src/lib.rs

// mod front_of_houseの後にブロックではなくセミコロンを使うと、Rustにモジュールの中身を`モジュールと同じ名前をした別のファイル`から読み込むように命令します。
// これは覚えておかないと
mod front_of_house;

pub use crate::front_of_house::hosting;

pub fn eat_at_restaurant() {
    hosting::add_to_waitlist();
}

以下のファイルの中身が src/lib.rs に展開される

// src/front_of_house.rs
pub mod hosting {
    pub fn add_to_waitlist() {}
}
Tatsushi KiryuTatsushi Kiryu

まとめ

  • パッケージ
    • Cargo.toml で管理される単位
    • 0 or 1 個のクレートを持つ
      • クレート
        • バイナリ or ライブラリのこと
        • 1個以上のモジュールを持つ
        • モジュールはファイルシステムのような階層構造を持ち、モジュールツリーと呼ばれる
        • ルートには crate と呼ばれるルートモジュールが必ず存在する
          • モジュール
          • クレート内のコードをグループ化し、可読性と再利用性を上げるためのもの
          • モジュールはデフォルトで private スコープ
            • 公開したい場合は pub キーワードを使う
            • ちなみに、構造体自体を pub にしても、そのフィールドは別途 pub 指定しないといけない
            • enum は pub にすると、variant 全て公開される
          • モジュールのパスを指定するには 絶対パス(crate)、相対パス(self)が使える
            • モジュールを import するには use キーワードを使う
              • 関数は、それが属するモジュールまでに留めておき、モジュール::関数() と呼び出すのが慣例的。
              • 構造体や enum の場合は、フルパスを指定するのが慣例的。
              • import したモジュールには as キーワードで別名を与えることができる。
              • pub use の組み合わせで re-export ができる。
              • 重複するパスはまとめて、差分のみを {} 内に記述できる。
              • wildcard で指定できる。
このスクラップは2021/07/10にクローズされました