Skip to content

book: some Crates and Modules nits #23401

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Merged
merged 1 commit into from
Mar 24, 2015
Merged
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
100 changes: 24 additions & 76 deletions src/doc/trpl/crates-and-modules.md
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
% Crates and Modules

When a project starts getting large, it's considered a good software
When a project starts getting large, it's considered good software
engineering practice to split it up into a bunch of smaller pieces, and then
fit them together. It's also important to have a well-defined interface, so
that some of your functionality is private, and some is public. To facilitate
Expand All @@ -24,23 +24,23 @@ in different languages. To keep things simple, we'll stick to "greetings" and
two languages for those phrases to be in. We'll use this module layout:

```text
+-----------+
+---| greetings |
| +-----------+
+---------+ |
| english |---+
+---------+ | +-----------+
| +---| farewells |
+---------+ | +-----------+
+-----------+
+---| greetings |
| +-----------+
+---------+ |
+---| english |---+
| +---------+ | +-----------+
| +---| farewells |
+---------+ | +-----------+
| phrases |---+
+---------+ | +-----------+
| +---| greetings |
+----------+ | +-----------+
| japanese |---+
+----------+ |
| +-----------+
+---| farewells |
+-----------+
+---------+ | +-----------+
| +---| greetings |
| +----------+ | +-----------+
+---| japanese |--+
+----------+ |
| +-----------+
+---| farewells |
+-----------+
```

In this example, `phrases` is the name of our crate. All of the rest are
Expand Down Expand Up @@ -76,25 +76,19 @@ To define each of our modules, we use the `mod` keyword. Let's make our
`src/lib.rs` look like this:

```
// in src/lib.rs

mod english {
mod greetings {

}

mod farewells {

}
}

mod japanese {
mod greetings {

}

mod farewells {

}
}
```
Expand Down Expand Up @@ -145,11 +139,7 @@ mod english;
```

If we do that, Rust will expect to find either a `english.rs` file, or a
`english/mod.rs` file with the contents of our module:

```{rust,ignore}
// contents of our module go here
```
`english/mod.rs` file with the contents of our module.

Note that in these files, you don't need to re-declare the module: that's
already been done with the initial `mod` declaration.
Expand Down Expand Up @@ -181,10 +171,7 @@ $ tree .
`src/lib.rs` is our crate root, and looks like this:

```{rust,ignore}
// in src/lib.rs

mod english;

mod japanese;
```

Expand All @@ -195,10 +182,7 @@ chosen the second. Both `src/english/mod.rs` and `src/japanese/mod.rs` look
like this:

```{rust,ignore}
// both src/english/mod.rs and src/japanese/mod.rs

mod greetings;

mod farewells;
```

Expand All @@ -214,8 +198,6 @@ both empty at the moment. Let's add some functions.
Put this in `src/english/greetings.rs`:

```rust
// in src/english/greetings.rs

fn hello() -> String {
"Hello!".to_string()
}
Expand All @@ -224,8 +206,6 @@ fn hello() -> String {
Put this in `src/english/farewells.rs`:

```rust
// in src/english/farewells.rs

fn goodbye() -> String {
"Goodbye.".to_string()
}
Expand All @@ -248,8 +228,6 @@ about the module system.
Put this in `src/japanese/farewells.rs`:

```rust
// in src/japanese/farewells.rs

fn goodbye() -> String {
"さようなら".to_string()
}
Expand All @@ -265,11 +243,9 @@ another crate.
We have a library crate. Let's make an executable crate that imports and uses
our library.

Make a `src/main.rs` and put this in it: (it won't quite compile yet)
Make a `src/main.rs` and put this in it (it won't quite compile yet):

```rust,ignore
// in src/main.rs

extern crate phrases;

fn main() {
Expand Down Expand Up @@ -320,8 +296,6 @@ keyword. Let's focus on the `english` module first, so let's reduce our `src/mai
to just this:

```{rust,ignore}
// in src/main.rs

extern crate phrases;

fn main() {
Expand All @@ -333,28 +307,20 @@ fn main() {
In our `src/lib.rs`, let's add `pub` to the `english` module declaration:

```{rust,ignore}
// in src/lib.rs

pub mod english;

mod japanese;
```

And in our `src/english/mod.rs`, let's make both `pub`:

```{rust,ignore}
// in src/english/mod.rs

pub mod greetings;

pub mod farewells;
```

In our `src/english/greetings.rs`, let's add `pub` to our `fn` declaration:

```{rust,ignore}
// in src/english/greetings.rs

pub fn hello() -> String {
"Hello!".to_string()
}
Expand All @@ -363,8 +329,6 @@ pub fn hello() -> String {
And also in `src/english/farewells.rs`:

```{rust,ignore}
// in src/english/farewells.rs

pub fn goodbye() -> String {
"Goodbye.".to_string()
}
Expand Down Expand Up @@ -400,8 +364,6 @@ Rust has a `use` keyword, which allows us to import names into our local scope.
Let's change our `src/main.rs` to look like this:

```{rust,ignore}
// in src/main.rs

extern crate phrases;

use phrases::english::greetings;
Expand Down Expand Up @@ -430,7 +392,7 @@ fn main() {
}
```

But it is not idiomatic. This is significantly more likely to introducing a
But it is not idiomatic: it is more likely to introduce a
naming conflict. In our short program, it's not a big deal, but as it grows, it
becomes a problem. If we have conflicting names, Rust will give a compilation
error. For example, if we made the `japanese` functions public, and tried to do
Expand Down Expand Up @@ -460,21 +422,19 @@ Could not compile `phrases`.
```

If we're importing multiple names from the same module, we don't have to type it out
twice. Rust has a shortcut syntax for writing this:
twice. Instead of this:

```{rust,ignore}
use phrases::english::greetings;
use phrases::english::farewells;
```

You use curly braces:
We can use this shortcut:

```{rust,ignore}
use phrases::english::{greetings, farewells};
```

These two declarations are equivalent, but the second is a lot less typing.

## Re-exporting with `pub use`

You don't just use `use` to shorten identifiers. You can also use it inside of your crate
Expand All @@ -484,8 +444,6 @@ interface that may not directly map to your internal code organization.
Let's look at an example. Modify your `src/main.rs` to read like this:

```{rust,ignore}
// in src/main.rs

extern crate phrases;

use phrases::english::{greetings,farewells};
Expand All @@ -503,18 +461,13 @@ fn main() {
Then, modify your `src/lib.rs` to make the `japanese` mod public:

```{rust,ignore}
// in src/lib.rs

pub mod english;

pub mod japanese;
```

Next, make the two functions public, first in `src/japanese/greetings.rs`:

```{rust,ignore}
// in src/japanese/greetings.rs

pub fn hello() -> String {
"こんにちは".to_string()
}
Expand All @@ -523,8 +476,6 @@ pub fn hello() -> String {
And then in `src/japanese/farewells.rs`:
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This also removes important information.

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

It should be obvious enough, which removes the need to point it out.

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

It's also mentioned earlier:

If we're importing multiple names from the same module, we don't have to type it out
twice. Rust has a shortcut syntax for writing this:

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I guess in my head, saying they're equivalent is important, and a 'shortcut' doesn't seem as strong.

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

There is also we don't have to type it out twice. So that's 3 mentions :)


```{rust,ignore}
// in src/japanese/farewells.rs

pub fn goodbye() -> String {
"さようなら".to_string()
}
Expand All @@ -533,13 +484,10 @@ pub fn goodbye() -> String {
Finally, modify your `src/japanese/mod.rs` to read like this:

```{rust,ignore}
// in src/japanese/mod.rs

pub use self::greetings::hello;
pub use self::farewells::goodbye;

mod greetings;

mod farewells;
```

Expand All @@ -551,9 +499,9 @@ module, we now have a `phrases::japanese::hello()` function and a
`phrases::japanese::farewells::goodbye()`. Our internal organization doesn't
define our external interface.

Here we have a `pub use` for each function we want to bring into the
Here we have a `pub use` for each function we want to bring into the
`japanese` scope. We could alternatively use the wildcard syntax to include
everything from `greetings` into the current scope: `pub use self::greetings::*`.
everything from `greetings` into the current scope: `pub use self::greetings::*`.

What about the `self`? Well, by default, `use` declarations are absolute paths,
starting from your crate root. `self` makes that path relative to your current
Expand Down