見出し画像

Rust学習 - モジュールの概念に入門(+α:cargo基本お作法を点検)

タイトルの通りもくもくと頑張る。画像は夜の空のイメージ。秋を先取りや。それにしてももうこんな時間。


本題

モジュールの概念に入門する。

ソースファイル作って中に関数掛けばいいんでしょ? super, self, use, modなんとなくわかる 定義を確認していきましょう。

モジュールとは

  • コードを階層的に分割し、お互いの機能を隠蔽・公開する仕組み。モジュールシステム。

    • Rustにはコードを階層的に分割し、お互いの機能を隠蔽・公開するための強力なモジュールシステムが存在します

  • モジュールは要素の集合です。

    • 要素とは

      • 関数(fn)

      • 構造体(struct)

      • トレイト(trait)

      • implブロック(impl)

      • さらには他のモジュール

      • など。

    • モジュールは「mod」キーワードを使って定義する

      • 関数「hello」を要素に持つ「my_mod」という名前のモジュールを実装した場合、以下のようなコードになる

mod my_mod {
  fn hello() {
    println!("Hello")
  } 
}

モジュールの特徴

モジュールの特徴を理解していく。

10.1. プライベートとパブリック

  • デフォルトでは、モジュール内の要素はプライベート

10.5. ファイルの階層構造

  • モジュールはファイル・ディレクトリ間の階層構造と対応関係にある

    • モジュールにお互いがどのように見えているか

      • これは、なんとなくは理解できる。

      • モジュールに定義された関数などを呼び出す側の視点で考える

        • モジュールに定義された関数などを呼び出す側で「mod my;」というコードを書いた場合

        • これは、「my.rs」という名前のファイル、もしくは、「my/mod.rs」 という名のファイルを探し、そのファイル内に実装されているモジュールの定義を、呼び出し側では「my」という名前で使用することができる。とかように解釈されるらしい。

10.4. super と self

  • 「self」

    • selfキーワードは現在のモジュールスコープを示す。

      • これはなんとなくわかる。つまりこういうことだ。

mod my {
  fn brother_function() {
    println!("called `brother_function()`");
  }
  struct Candy {
    price: u32,
    flavor: String,
    size: u8,
  }
  impl Candy {
    pub fn new(price: u32, falvor: String, size:u8) -> Self {
      Candy {
        price,
        flavor,
        size,
      } 
    } 
  }
  pub fn hello() {
    // `super`は親スコープ(`my`の外側)を参照する。
    self::brother_function();
    let orange = self::Candy::new(10000, "orange", 1)
  }
}
  • 「super」

    • 「super」とは、「my」モジュールの外側、親スコープを参照することを意味する。

      • 親スコープ。。?

        • 今度はモジュール定義する側の視点で考える

          • 仮に「my」というモジュールを定義して、その親スコープに定義された「parent_function」という関数を参照するケースを考えると、以下のようなコードになる。

fn parent_function() {
  println!("called `parent_function()`");
}

mod my {
  pub fn hello() {
    // `super`は親スコープ(`my`の外側)を参照する。
    super::parent_function();
  }
}
  • use宣言「要素の絶対パスを新しい名前にバインドする」という意味を持つらしい。

    • 説明はいまいちピンとこないが、定義済みのモジュールを呼びやすくする仕組みと理解した。

    • 説明によれば、「use super::*;」と宣言すると、親スコープの関数をsuper::の記載なしに呼び出せるらしい。

  • つまり、以下のような2つのモジュールが同じフォルダにあった時

    • 「you」モジュールの関数を使用することをmain関数を定義したモジュール内で宣言し、必要に応じて、as句で名前をつけるという使い方をする。ここでは「」

      • src/you.rs

mod you {
  pub fn greeting(who: &str) {
    println!("Hi {}", *str);
  }
}
  • src/main.rs


use you::greeting as hi_bob;

fn main() {
    // `you::greeting` 関数の定義が実行される
    let bob:  String = "Bob";
    hi_bob(bob);
}

以上。モジュールについてなんとなく理解した。

余談(命名について)

本題+α

cargoの使い方と定義を確認する時間だ。

ドキュメントざっくり読んだが、しっくり来る説明がない。コマンドを勘で実行してる。実際の挙動は見てなんとなくわかる。定義がどのようになっているのかを知りたい。

概念を理解し、それから実践していく。

cargo概念理解

CargoRustのビルドシステム兼パッケージマネージャ

以下の2つのドキュメントを熟読したところ、概念を理解することができた。結構わかりにくいな。

  • cargo

    • 依存関係の管理

      • crates.io(Rustの公式パッケージレジストリ)とのインテグレーション

        • バイナリを作る

          • プロジェクトをビルドする/cargo build/全ての依存関係の解決/必要なクレートのダウンロード/自分のクレートを含む全てのビルド

          • プロジェクトをビルドして更に実行する/cargo run

          • バイナリクレートをローカルにインストール/cargo install/バイナリ=たぶん実行形式ファイルのこと。bin/クレート=ライブラリに相当する概念

    • crates.io

      • Rustのデフォルトパッケージレジストリ(Rust community's central package registry

cargo実践確認(バイナリを作る)

バージョン確認

$ asdf current rust
rust            1.62.1          /Users/e_fujikawa/.tool-versions
$ cargo --version
cargo 1.62.1 (a748cf5a3 2022-06-08)

パッケージビルド

$ cargo build --release
   Compiling libc v0.2.126
   Compiling hex v0.3.2
   Compiling commoncrypto-sys v0.2.0
   Compiling commoncrypto v0.2.0
   Compiling crypto-hash v0.3.4
   Compiling blockchain-in-rust v0.1.0
    Finished release [optimized] target(s) in 2.60s

cargo の挙動、基本的なことを知りたいだけなのに、公式のドキュメント深く全部読まないとわからない。必要な情報が出てこない。

「プロジェクトをビルドする/cargo build/全ての依存関係の解決/必要なクレートのダウンロード/自分のクレートを含む全てのビルド」で理解できた。

またあした!

この記事が気に入ったらサポートをしてみませんか?