// 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
この辞書が使われているページ
backlinks 5