![](https://doc.rust-lang.org/book/second-edition/]
Apache License Version 2.0
Controlling Visibility with pub
今まで作ってきたライブラリ(ドンガラだが)を外から使ってみる.それには,communicator/src/main.rsを作成して,その中でcommunicatorを呼び出せば良い.
src/main.rs
extern crate communicator;
fn main() {
communicator::client::connect();
}
ここでcargo build
すると,
shell
error: module `client` is private
--> src/main.rs:4:3
|
4 | communicator::client::connect();
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
error: aborting due to previous error
error: Could not compile `communicator`.
To learn more, run the command again with --verbose.
とエラーが出る.client
moduleがprivateであるというエラーである.
Making a Function Public
pub
キーワードによってfunctionやmoduleをpublicにできる.
client
ライブラリをpublicにするには,
src/main.rs
pub mod client;
mod network;
とする.ここでcargo build
しても,
error: module `client` is private
--> src/main.rs:4:3
|
4 | communicator::client::connect();
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
と怒られる.今度はsrc/client.rsを書き換えてclient::connect
をpublicにすると,ビルドできるようになる.
warning: function is never used: `connect`
--> src/network/mod.rs:1:1
|
1 | fn connect() {
| _^ starting here...
2 | | }
| |_^ ...ending here
|
= note: #[warn(dead_code)] on by default
Finished dev [unoptimized + debuginfo] target(s) in 0.53 secs
という警告は,network::connectがprivateで,そのライブラリプロジェクトの中でも使われていないから起こる.network::connectとnetwork::server::connectもpublicにする.
Privacy Rules
- あるアイテムがpublicであるとき,親moduleを通じてそのアイテムにアクセスできる.
- あるアイテムがprivateであるとき,そのアイテムがあるmoduleとその子moduleからしかそのアイテムにはアクセスできない.
Privacy Examples
mod outermost { // private
pub fn middle_function() {} // public in private
fn middle_secret_function() {} // private
mod inside { // private in private
pub fn innner_function() {} // public in private in private
fn secret_function() {} // private in private in private
}
}
fn try_me() {
outermost::middle_function(); // PrivateRule1より,accessible
outermost::middle_secret_function(); // PrivateRule2より,unaccessible
outermost::inside::inner_function(); // PrivateRule2より,accessible
outermost::inside::secret_function(); // PrivateRule2より,unaccessible
}
Importing Names
src/main.rs
pub mod a {
pub mod series{
pub mod of {
pub fn nested_modules() {}
}
}
}
fn main() {
a::series::of::nested_modules();
}
のように,module1の中のmodule2,module1の中のfunction1を指定するときには,module1::module2
とかmodule1::function1
とするのだった.
こうした記法では呼び出しが長くなりすぎる危険があるので,より簡潔に呼ぶ方法が実装されている.
Concise Imports with use
src/main.rs
pub mod a {
pub mod series{
pub mod of {
pub fn nested_modules() {}
}
}
}
use a::series::of;
fn main() {
of::nested_modules();
}
このように,use
によって内側にあるmoduleを現時点の名前空間から記述して名前空間に入れることで,そのmoduleの名前だけでそのmoduleを特定できる.
enum
もまた名前空間を作るので,use
によってenum
を簡潔に書ける.同じ名前空間から複数の要素をuse
によって今の名前空間に入れるときは{}でまとめられる.
enum TrafficLight {
Red,
Yellow,
Green,
}
use TrafficLight::{Red, Yellow};
fn main() {
let red = Red;
let yellow = Yellow;
let green = TrafficLight::Green
}
### Glob Imports with ```*```
ある名前空間の中の全てを今の名前空間に入れたいとき,```*```を使う.
```rust
enum TrafficLight {
Red,
Yellow,
Green,
}
use TrafficLight::*;
fn main() {
let red = Red;
let yellow = Yellow;
let green = Green;
}
<div class="se-preview-section-delimiter"></div>
*
をglobという.便利だがバグの温床となるので使うときは慎重に考えるべき.
Using super
to Access a Parent Module
ライブラリを作成するとき,Cargoは同時にtests
moduleを作成する.これについて詳しく述べる.
src/lib.rs
pub mod client;
pub mod network;
<div class="se-preview-section-delimiter"></div>
#[cfg(test)]
mod tests {
#[test]
fn it_works() {
}
}
<div class="se-preview-section-delimiter"></div>
この時点でのcommunicator
の階層構造は
communicator
├── client
├── network
| └── client
└── tests
```
となっている.```tests::it_works```に```client::connect```を実行するコードを入れてみよう.
*src/lib.rs*
```rust
#[cfg(test)]
mod tests {
#[test]
fn it_works() {
client::connect();
}
}
```
```cargo test```を実行する.
*shell*
```bash
warning: function is never used: `connect`
--> src/network/mod.rs:1:1
|
1 | pub fn connect() {
| _^ starting here...
2 | | }
| |_^ ...ending here
|
= note: #[warn(dead_code)] on by default
error[E0433]: failed to resolve. Use of undeclared type or module `client`
--> src/lib.rs:8:5
|
8 | client::connect();
| ^^^^^^^^^^^^^^^ Use of undeclared type or module `client`
error: aborting due to previous error
error: Could not compile `communicator`.
Build failed, waiting for other jobs to finish...
error: build failed
<div class="se-preview-section-delimiter"></div>
rustの中の名前空間は相対的で,tests
の中からclient::connect
を呼ぶには,一度上の階層に登ってからclient::connect
を呼ばなければならない.ただし,usr
で呼ぶ場合はルートから名前を指定する.
::
を最初につけることで,絶対的に階層を指定できる.例えば::client::connect()
とすれば,tests
の中からclient::connect
を呼べる.あるいは,super
キーワードで一つ上の階層に登って,client::connect
を呼ぶこともできる.このばあいsuper::client::connect
とする.
bashで例えるなら,super
は.
と,::
は/
に対応する.
src/lib.rs
mod network;
pub mod client;
#[cfg(test)]
mod tests {
#[test]
fn it_works() {
client::connect();
}
}
としてcargo test
すると,
shell
Running target/debug/deps/communicator-428d4111ad386458
running 1 test
test tests::it_works ... ok
test result: ok. 1 passed; 0 failed; 0 ignored; 0 measured
と,無事テストが完了する.
Running target/debug/deps/communicator-428d4111ad386458
running 1 test
test tests::it_works ... ok
test result: ok. 1 passed; 0 failed; 0 ignored; 0 measured
と,無事テストが完了する.
0 件のコメント:
コメントを投稿