Progrust Library.

// article

Rust Playgroundで複数ファイルが扱えるように!.

Rust PlaygroundはRustのコードをブラウザ上で実行できる便利なサイトですが、いままでは単一ファイルの実行しかできませんでした。
それがいつのまにか複数ファイルにコードを分けて実行できるようになっていました!

マルチファイルを有効にするにはCONFIGのEdit Filesで「MULTIPLE」に変更する必要があるようです。

マルチファイルへ設定変更するスクリーンショット

検証

このマルチファイルモードでなにができるのか、軽く検証していきます。

1. 通常のモジュール分割

Cargoプロジェクトと同じモジュール解決が効いているか検証。

// project

通常のモジュール分割

2 files

Playgroundで開く
src/
greetings.rs
main.rs
src/greetings.rs
pub fn hello(name: &str) -> String {
    format!("こんにちは、{}さん", name)
}

pub const VERSION: u32 = 1;
src/main.rs
mod greetings;

fn main() {
    println!("{}", greetings::hello("太郎"));
    println!("version = {}", greetings::VERSION);
}

できる!

通常のモジュール分割の検証結果スクリーンショット

実行結果

2. サブディレクトリ

ファイル作成時にsrc/utils/math.rsのようなパス付きの名前でディレクトリが作れるかどうか検証。

// project

サブディレクトリ構成

3 files

Playgroundで開く
src/
utils/
math.rs
main.rs
utils.rs
src/utils.rs
pub mod math;

pub fn label() -> &'static str {
    "utils module"
}
src/utils/math.rs
pub fn add(a: i32, b: i32) -> i32 {
    a + b
}
src/main.rs
mod utils;

fn main() {
    println!("{} / 1 + 2 = {}", utils::label(), utils::math::add(1, 2));
}

できる!

サブディレクトリの検証結果スクリーンショット

実行結果

3. lib.rsとの共存

src/lib.rsを作ると、バイナリ側からライブラリクレートとして参照できるはず。Playgroundのクレート名はplaygroundなのでuse playground::...で解決されるか?

// project

lib.rsとバイナリの共存

2 files

Playgroundで開く
src/
lib.rs
main.rs
src/lib.rs
pub struct Counter {
    count: u32,
}

impl Counter {
    pub fn new() -> Self {
        Self { count: 0 }
    }

    pub fn increment(&mut self) -> u32 {
        self.count += 1;
        self.count
    }
}
src/main.rs
use playground::Counter;

fn main() {
    let mut c = Counter::new();
    c.increment();
    c.increment();
    println!("count = {}", c.increment()); // 3
}

できる!

lib.rsとの共存の検証結果スクリーンショット

実行結果

4. lib側でユニットテスト実行

lib側だけに#[cfg(test)] mod testsを書いてTOOLSの「Test」でユニットテストを回すことができるか検証。

// project

lib側のユニットテスト

1 file

Playgroundで開く
src/
lib.rs
src/lib.rs
pub struct Counter {
    count: u32,
}

impl Counter {
    pub fn new() -> Self {
        Self { count: 0 }
    }

    pub fn increment(&mut self) -> u32 {
        self.count += 1;
        self.count
    }
}

#[cfg(test)] 
mod tests { 
    use super::*; 
    #[test] 
    fn counter_increments() { 
        let mut c = Counter::new(); 
        assert_eq!(c.increment(), 1); 
        assert_eq!(c.increment(), 2); 
    } 
} 

できる!

lib側でユニットテスト実行の検証結果スクリーンショット

実行結果

5. Rustコード以外のファイルを作成

data.txtのような.rs以外の拡張子を作成して読み込めるか検証。

// project

Rust以外のファイルの読み込み

2 files

Playgroundで開く
src/
data.txt
main.rs
src/data.txt
Hello from data file!
src/main.rs
fn main() {
    let data = include_str!("data.txt");
    println!("読み込んだ内容: {}", data);
}

できる!

Rustコード以外のファイルを作成の検証結果スクリーンショット

実行結果

まとめ

マルチファイルモードの追加によって、「単一ファイルのスニペット実行環境」から「小規模なCargoプロジェクトをまるごと再現できる環境」に変わった感じがします。
モジュール設計や可視性(pub / pub(crate))の挙動確認、初学者向け資料でのプロジェクト構成の説明、複数ファイルが絡むバグの再現・共有などなど、いろいろな使い道がありそうです。