pub
を付与すると公開(public)される。pub
がなければ非公開(private)。
成果物
参照
pub
main.rs
fn main() { println!("{}", my_mod::public()); // println!("{}", my_mod::private()); // error[E0603]: function `private` is private } mod my_mod { pub fn public() -> String { String::from("my_mod::public()") } fn private() -> String { String::from("my_mod::private()") } }
fn
の前にpub
があると参照可。ないと不可。
プライバシー規則
プライバシー規則によると以下。
- 要素が公開(
pub
)なら、どの親モジュールを通してもアクセス可 - 要素が非公開なら、直接の親モジュールとその親の子モジュールのみアクセス可
非公開
非公開のときのがちょっとわかりにくい。ので自分用にまとめる。privateな要素を参照できるのは以下だけである。
- private要素を定義したモジュールから参照可
- 上記の子(子孫)モジュールから参照可
逆にprivate要素を参照できないのは以下。
- private要素を定義したモジュールの親(先祖)モジュールから参照不可
同一モジュール内なら参照可
最初のコード例でいうとmy_mod
モジュール内でのみ参照可。たとえばmy_mod
内のpublic()
関数内ではprivate()
関数を参照できる。
mod my_mod { pub fn public() -> String { private(); String::from("my_mod::public()") } fn private() -> String { String::from("my_mod::private()") } }
子孫モジュールなら参照可
my_mod
の子モジュールからもprivateを参照できる。super::private();
がそれ。親モジュールのprivate要素を参照している。
mod my_mod { pub fn public() -> String { private(); String::from("my_mod::public()") } fn private() -> String { String::from("my_mod::private()") } mod my_mod_1 { pub fn public() -> String { super::private(); String::from("my_mod::public()") } } }
また、孫からも参照できる。super::super::private();
がそれ。
mod my_mod { pub fn public() -> String { private(); String::from("my_mod::public()") } fn private() -> String { String::from("my_mod::private()") } mod my_mod_1 { pub fn public() -> String { super::private(); String::from("my_mod::my_mod_1::public()") } fn private() -> String { String::from("my_mod::my_mod_1::private()") } mod my_mod_2 { pub fn public() -> String { super::super::private(); super::private(); String::from("my_mod::my_mod_1::public()") } } } }
無駄な考察をしてみた。
子モジュール側から参照できるのは、他言語でいうとC#のクラス継承におけるprotected
に似ている? でも、同名メンバだとthis.member
で自分か最も近い親の定義を参照するし、base.member
だと自分を除く最も近い親の定義を参照する。つまりそれより上にある同名メンバは参照できない。Rustではsuper
で1階層ずつ指定せねばならないが、すべて個別に指定できる。継承の概念とは違うため。
なぜprivateは自分のモジュール内だけでなく子孫モジュールから参照されてしまうのか。privateなら自モジュールのみ参照ではないのか。アクセスを細かく制御できるようにさせると複雑化するから? たとえばC#のアクセス修飾子は6種類もある。
そもそも同一モジュール内しか使わないという場合が少ない? いやあるだろう。
略記するため? 子孫モジュールからも参照できるようにすることでprotected
的な修飾子を不要にする。そうすれば修飾子はpublicとprivate(protected
)の2種類しかなくなる。2種類だけならpub
を省略したときは必ずprivateとして断定できる。これにより略記可能。短いコードで書くことができる。
親モジュールからは参照不可
最初のコードでmain()
関数内でmy_mod::private()
を呼び出せなかった。理由はmain()
関数が定義されたモジュールmain
はmy_mod
の親モジュールだから。
(Rust言語においてmain.rs
ファイル内はルートとなるモジュールでありmain()
関数はエントリポイントとなる特殊関数)
main.rs
fn main() { println!("{}", my_mod::public()); // println!("{}", my_mod::private()); // error[E0603]: function `private` is private } mod my_mod { pub fn public() -> String { String::from("my_mod::public()") } fn private() -> String { String::from("my_mod::private()") } }
「private要素は、先祖からは見えないのに子孫からは見れる」というのが直感的でない気がした。たぶんRust言語でprivate
と言われているものは、今まで慣れ親しんできたオブジェクト指向におけるprotected
相当だからだろう。
覚えやすい考え方はないか。
ソフトウェアは上位モジュールほど抽象化されてあるもの。そのため細かい処理は隠蔽されたほうが俯瞰しやすい。親側ほど参照できる要素を減らしたい。そう考えれば覚えやすいか?
まとめ
pub
を要素の前に付与すると、そのモジュールを介してアクセス可pub
がないと、それを定義したモジュールとその子孫モジュールのみアクセス可
不明瞭
なお、pub
の対象となる要素は以下だと思う。
mod
,fn
,struct
,enum
,trait
たぶんimpl
の前にpub
は付与しないと思うのだが、どうなの?
trait
はまだ学習してないから知らん。でもググると以下でpub trait ...
というコードを見た。
前回まで
- Rustを学んでみたい(プログラミング言語)
- Rustの環境構築
- RustでHelloWorld
- Rustの和訳ドキュメント
- Cargoでプロジェクト作成・ビルド・実行
- クレートとは?
- Rustで関数を使ってみる
- Rustでモジュールを使ってみる
- Rustで乱数を生成する(rand)
- Rustで標準入力する(std::io::stdin().read_line())
- RustでMatch判定する(match)
- Rustでprintとread_lineを1行にする方法
- Rustで数当てゲーム
- クレート名にドット.が使えない
- Rustの変数と可変性(let, mut) error[E0384]: cannot assign twice to immutable variable
x
- Rustのimmutable束縛とconst定数の違い
- RustのREPL、evcxrのインストールに失敗した
- Rustでコンパイルするときの変数未使用warningを消す
- Rustの変数(再代入、再宣言(シャドーイング))
- Rustのシャドーイングについて
- イミュータブルについて(副作用)
- Rustの定数(const)
- Rustのデータ型(数値)
- Rustのデータ型(論理)
- Rustのデータ型(文字)
- Rustのデータ型(タプル)
- Rustのデータ型(配列)
- Rustの関数
- Rustのif式
- Rustのくりかえし文(loop)
- Rustのくりかえし文(while)
- Rustのくりかえし文(for)
- Rustの所有権(ムーブ)
- Rustの所有権(関数)
- Rustの所有権(スライス)
- Rustの構造体(定義とインスタンス化)
- Rustの構造体(プログラム例)
- Rustの構造体(メソッド)
- Rustの列挙型(enum)
- Rustの列挙型(enum)
- Rustの列挙型(enum)
- Rustのmatch(制御フロー演算子)
- RustでNULLを扱う(Option, Some, None)
- NULL参照は10億ドルの失敗だった
- Rustの列挙型に独自表示を実装する(E0277 対策 std::fmt::Display 実装)
- RustのIfLet(matchの糖衣構文)
- Rustのプロジェクト構造
- Rustのcargoでライブラリ&テスト(単体、結合)
- Rustのモジュール(mod)