// dictionary
再エクスポート.
再エクスポートは、use宣言にpubを付けてpub useと書き、持ち込んだ名前をそのモジュールの外へも公開することです1。ある場所にある公開された項目を別の場所で公開し直し、あたかもそちらで定義されたかのように使わせられます2。
これにより、内部のモジュール構造と、外から見える公開APIの形を切り離せます。使う側は深い階層をパス(Path)でたどらずに済み、作る側は内部の階層をあとから組み替えられます2。
/// カートに入れた商品の価格(`lib.rs`から再エクスポートするので`pub`にする)
pub struct Cart {
prices: Vec<u32>,
}
impl Cart {
pub fn new(prices: Vec<u32>) -> Self {
Cart { prices }
}
/// 送料込みの合計金額(3000円以上は送料無料)
pub fn total(&self) -> u32 {
let subtotal: u32 = self.prices.iter().sum();
if subtotal >= 3000 { subtotal } else { subtotal + 500 }
}
}// `pub`を付けないので、`price`モジュール自体は外から見えない
mod price;
// 使ってほしいものだけをクレートルートで公開する
pub use crate::price::Cart;// 内部の`price`は隠れたまま、`Cart`だけが短いパスで使える
use playground::Cart; // ライブラリのクレート名(Playgroundでは playground 固定)
fn main() {
let cart = Cart::new(vec![1200, 800]);
println!("お支払い金額: {}円", cart.total()); // 2500円
}内部構造と公開APIを分ける
mod price;にはpubが付いていないため、priceモジュールはクレートの外から見えません(モジュールのファイル分割も参照)。それでも外からplayground::Cartと書けるのは、Cartへの経路が再エクスポートによって開かれるからです。The Rust Referenceはこれを、通常のように名前空間の階層をたどる代わりに「プライバシーの連鎖が再エクスポートを通じて短絡される」と表現しています3。
使う側が書くパスは次のように変わります。
| 公開のしかた | 使う側が書くパス | priceモジュール |
|---|---|---|
| 再エクスポートなし | use playground::price::Cart; |
pub modにする必要がある |
| 再エクスポートあり | use playground::Cart; |
非公開のまま隠せる |
公開APIが内部構造から切り離されるため、あとでpriceを分割・改名しても、直すのはクレートの中だけで済み、使う側のコードには影響しません。
使いどころ
クレートを使う人は作者ほど内部の構造に詳しくないので、公開APIの形は公開時の重要な検討事項になります2。
| 場面 | ねらい |
|---|---|
| 深い階層にある型や関数を集める | 使う側がuse my_crate::UsefulType;と短く書ける。cargo docのトップページにも載る2 |
| 実装用のモジュールを非公開のまま隠す | 公開したい項目だけを通し、内部はあとから自由に変更できる3 |
| プレリュードを用意する | まとめて取り込ませたいAPI群を1つのモジュールに集め、use my_crate::prelude::*;で使わせる4 |
補足
再エクスポートできるのはpubな項目だけ
pub useで公開し直せるのは、それ自体にpubが付いた項目だけです。隠せるのは経路であって項目そのものではないため、非公開モジュールの中のpubな項目は再エクスポートできますが、pubの付いていない項目は同じモジュールからでも再エクスポートできずE0364になります。
mod shop {
// `pub`が付いていない=非公開の関数
fn subtotal(prices: &[u32]) -> u32 {
prices.iter().sum()
}
// エラー: E0364(`pub`でない項目は再エクスポートできない)
pub use self::subtotal as sum;
}
fn main() {}
再エクスポートで作った名前は正規パスではない
項目の正規パスはそれが定義された場所で決まり、同じ項目を指す他のパスはすべて別名として扱われます5。上のライブラリでいえば、Cartの正規パスはcrate::price::Cartのままで、pub useで作ったplayground::Cartはそこへの別名です(パス(Path)も参照)。
公開範囲を絞る・まとめて再エクスポートする
pub useのほかに、公開範囲の指定やglob演算子と組み合わせた書き方もあります。
| 書き方 | 意味 |
|---|---|
pub use crate::price::Cart; |
制限なしで再エクスポート(外部クレートからも使える) |
pub(crate) use crate::price::Cart; |
同じクレートの中だけに見せる(内部向けの共通の入口) |
pub use crate::price::*; |
priceの中の持ち込める項目をまとめて再エクスポート |
再エクスポートは公開する名前を別の定義へリダイレクトする働きを持つため、リダイレクトが循環したり一意に解決できなかったりする場合はコンパイルエラーになります1。
Footnotes
この辞書が使われているページ
backlinks 7