Progrust Library.

// dictionary

super.

superは、パスの先頭に置いて親モジュールを起点にするキーワードです1。ファイルシステムのパスを..で始めて1つ上のディレクトリへ上がるのと同じ感覚で、モジュールツリーを1段上に登ってから、目的の関数や型をたどります2

superを書けるのはパスの先頭部分だけです(先頭にselfを置いた直後も可)。super::super::のように連ねれば、さらに上の祖先モジュールも指せます1

fn log(message: &str) {
    println!("[ログ] {}", message);
}

mod shop {
    const TAX_RATE: u32 = 10;

    fn with_tax(price: u32) -> u32 {
        price * (100 + TAX_RATE) / 100
    }

    pub mod cart {
        pub fn checkout(prices: &[u32]) -> u32 {
            let subtotal: u32 = prices.iter().sum();
            let total = super::with_tax(subtotal); // 1段上(shop)をたどる
            super::super::log("会計しました"); // 2段上(クレートルート)をたどる
            total
        }
    }
}

fn main() {
    println!("お支払い金額: {}円", shop::cart::checkout(&[980, 1250]));
}
Playgroundで開く
crate          // super::super の指す先
└── shop       // super の指す先
    └── cart   // checkout はここにいる

パスの先頭に書けるキーワード

superは、パス(Path)の先頭に書けるキーワードの1つです。クレートのルートを起点にするcrateとの違いは次のとおりです。

先頭に書く語 起点 ファイルシステムでの例え
crate クレートのルート /
self 現在のモジュール ./
super 親モジュール ../

使いどころ

superが向くのは、親モジュールと一緒に移動する可能性が高いコードです。定義と呼び出しの位置関係が変わらないなら、そのまとまりごと別の場所へ移してもパスを書き直さずに済みます2

その典型が、テスト対象と同じファイルに置く#[cfg(test)]付きのテストモジュールです。use宣言use super::*;と書けば、親モジュール(慣例どおりファイル直下に置いたなら、そのファイルのトップレベル)の項目を、非公開のものまでまとめて取り込めます3

fn with_tax(price: u32) -> u32 {
    price * 110 / 100
}

#[cfg(test)]
mod tests {
    use super::*; // 親モジュールの項目をまとめて取り込む

    #[test]
    fn tax_is_added() {
        assert_eq!(with_tax(1000), 1100); // 非公開のwith_taxも呼べる
    }
}

fn main() {
    println!("税込: {}円", with_tax(1000));
}
Playgroundで開く

補足

クレートルートより上へは登れない

クレートルートのモジュールには親がないため、そこでsuperを書くとコンパイルエラーになります。super::super::を重ねすぎて祖先を通り越した場合も同じです(Rust 1.93で確認)。

mod shop {
    pub fn checkout() {}
}

fn main() {
    // エラー: E0433(先頭の`super`が多すぎる)
    super::shop::checkout();
}
use宣言で使う場合

use宣言の先頭にもsuperを書けます(use super::with_tax;)。親モジュールそのものを取り込むときはasで別名を付ける必要があり、use super as parent;は書けますがuse super;は書けません4。ただし別名付きで取り込めるようになったのはRust 1.95からで、1.94以前はuse super as parent;もE0432になります5

2015エディションではuseのパスがクレートルート起点だったため、親モジュールの項目を取り込むにもsuper::を明示する必要がありました。2018エディション以降は現在のスコープからの相対解決になっています4

可視性を指定する pub(super)

superという語は、可視性の指定にも現れます。pubに丸括弧を添えたpub(super)は項目を親モジュールにだけ見せる指定で、pub(in super)と同じ意味です6。パスの先頭に書くsuperとは文法上の位置が異なるため、混同しないよう注意してください。

Footnotes

  1. Paths — The Rust Reference 2

  2. Starting Relative Paths with super — The Rust Programming Language 2

  3. Test Organization — The Rust Programming Language

  4. Use declarations — The Rust Reference 2

  5. Support importing path-segment keyword with renaming — rust-lang/rust #146972(Rust 1.95.0で導入)

  6. Visibility and Privacy — The Rust Reference

この辞書が使われているページ

backlinks 5

  1. 辞書pub
  2. 辞書use宣言
  3. 辞書パス(Path)
  4. 辞書モジュールのファイル分割
  5. 動かして学ぶRustプログラミング問題集 › 第14章 パスとuse宣言