2015-01-16 14:30:27 -06:00
|
|
|
|
% Crates and Modules
|
2014-09-25 23:20:25 -05:00
|
|
|
|
|
2015-04-21 12:17:43 -05:00
|
|
|
|
When a project starts getting large, it’s considered good software
|
2014-09-25 23:20:25 -05:00
|
|
|
|
engineering practice to split it up into a bunch of smaller pieces, and then
|
2015-04-21 12:17:43 -05:00
|
|
|
|
fit them together. It’s also important to have a well-defined interface, so
|
2014-09-25 23:20:25 -05:00
|
|
|
|
that some of your functionality is private, and some is public. To facilitate
|
|
|
|
|
these kinds of things, Rust has a module system.
|
|
|
|
|
|
|
|
|
|
# Basic terminology: Crates and Modules
|
|
|
|
|
|
2015-04-21 12:17:43 -05:00
|
|
|
|
Rust has two distinct terms that relate to the module system: ‘crate’ and
|
|
|
|
|
‘module’. A crate is synonymous with a ‘library’ or ‘package’ in other
|
|
|
|
|
languages. Hence “Cargo” as the name of Rust’s package management tool: you
|
2014-09-25 23:20:25 -05:00
|
|
|
|
ship your crates to others with Cargo. Crates can produce an executable or a
|
2015-02-19 20:39:38 -06:00
|
|
|
|
library, depending on the project.
|
2014-09-25 23:20:25 -05:00
|
|
|
|
|
2015-01-08 18:52:50 -06:00
|
|
|
|
Each crate has an implicit *root module* that contains the code for that crate.
|
2014-09-25 23:20:25 -05:00
|
|
|
|
You can then define a tree of sub-modules under that root module. Modules allow
|
|
|
|
|
you to partition your code within the crate itself.
|
|
|
|
|
|
2015-04-21 12:17:43 -05:00
|
|
|
|
As an example, let’s make a *phrases* crate, which will give us various phrases
|
|
|
|
|
in different languages. To keep things simple, we’ll stick to ‘greetings’ and
|
|
|
|
|
‘farewells’ as two kinds of phrases, and use English and Japanese (日本語) as
|
|
|
|
|
two languages for those phrases to be in. We’ll use this module layout:
|
2014-09-25 23:20:25 -05:00
|
|
|
|
|
|
|
|
|
```text
|
2015-03-13 22:55:01 -05:00
|
|
|
|
+-----------+
|
|
|
|
|
+---| greetings |
|
|
|
|
|
| +-----------+
|
|
|
|
|
+---------+ |
|
|
|
|
|
+---| english |---+
|
|
|
|
|
| +---------+ | +-----------+
|
|
|
|
|
| +---| farewells |
|
|
|
|
|
+---------+ | +-----------+
|
2014-12-09 12:26:04 -06:00
|
|
|
|
| phrases |---+
|
2015-03-13 22:55:01 -05:00
|
|
|
|
+---------+ | +-----------+
|
|
|
|
|
| +---| greetings |
|
|
|
|
|
| +----------+ | +-----------+
|
|
|
|
|
+---| japanese |--+
|
|
|
|
|
+----------+ |
|
|
|
|
|
| +-----------+
|
|
|
|
|
+---| farewells |
|
|
|
|
|
+-----------+
|
2014-09-25 23:20:25 -05:00
|
|
|
|
```
|
|
|
|
|
|
|
|
|
|
In this example, `phrases` is the name of our crate. All of the rest are
|
|
|
|
|
modules. You can see that they form a tree, branching out from the crate
|
2015-01-08 18:52:50 -06:00
|
|
|
|
*root*, which is the root of the tree: `phrases` itself.
|
2014-09-25 23:20:25 -05:00
|
|
|
|
|
2015-04-21 12:17:43 -05:00
|
|
|
|
Now that we have a plan, let’s define these modules in code. To start,
|
2014-09-25 23:20:25 -05:00
|
|
|
|
generate a new crate with Cargo:
|
|
|
|
|
|
|
|
|
|
```bash
|
|
|
|
|
$ cargo new phrases
|
|
|
|
|
$ cd phrases
|
|
|
|
|
```
|
|
|
|
|
|
|
|
|
|
If you remember, this generates a simple project for us:
|
|
|
|
|
|
|
|
|
|
```bash
|
|
|
|
|
$ tree .
|
|
|
|
|
.
|
|
|
|
|
├── Cargo.toml
|
|
|
|
|
└── src
|
|
|
|
|
└── lib.rs
|
|
|
|
|
|
|
|
|
|
1 directory, 2 files
|
|
|
|
|
```
|
|
|
|
|
|
|
|
|
|
`src/lib.rs` is our crate root, corresponding to the `phrases` in our diagram
|
|
|
|
|
above.
|
|
|
|
|
|
|
|
|
|
# Defining Modules
|
|
|
|
|
|
2015-04-21 12:17:43 -05:00
|
|
|
|
To define each of our modules, we use the `mod` keyword. Let’s make our
|
2014-09-25 23:20:25 -05:00
|
|
|
|
`src/lib.rs` look like this:
|
|
|
|
|
|
2015-05-18 13:56:00 -05:00
|
|
|
|
```rust
|
2014-09-25 23:20:25 -05:00
|
|
|
|
mod english {
|
|
|
|
|
mod greetings {
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
mod farewells {
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
mod japanese {
|
|
|
|
|
mod greetings {
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
mod farewells {
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
```
|
|
|
|
|
|
|
|
|
|
After the `mod` keyword, you give the name of the module. Module names follow
|
|
|
|
|
the conventions for other Rust identifiers: `lower_snake_case`. The contents of
|
|
|
|
|
each module are within curly braces (`{}`).
|
|
|
|
|
|
|
|
|
|
Within a given `mod`, you can declare sub-`mod`s. We can refer to sub-modules
|
|
|
|
|
with double-colon (`::`) notation: our four nested modules are
|
|
|
|
|
`english::greetings`, `english::farewells`, `japanese::greetings`, and
|
|
|
|
|
`japanese::farewells`. Because these sub-modules are namespaced under their
|
2015-04-21 12:17:43 -05:00
|
|
|
|
parent module, the names don’t conflict: `english::greetings` and
|
2014-09-25 23:20:25 -05:00
|
|
|
|
`japanese::greetings` are distinct, even though their names are both
|
|
|
|
|
`greetings`.
|
|
|
|
|
|
|
|
|
|
Because this crate does not have a `main()` function, and is called `lib.rs`,
|
|
|
|
|
Cargo will build this crate as a library:
|
|
|
|
|
|
|
|
|
|
```bash
|
|
|
|
|
$ cargo build
|
|
|
|
|
Compiling phrases v0.0.1 (file:///home/you/projects/phrases)
|
2015-04-02 16:15:28 -05:00
|
|
|
|
$ ls target/debug
|
|
|
|
|
build deps examples libphrases-a7448e02a0468eaa.rlib native
|
2014-09-25 23:20:25 -05:00
|
|
|
|
```
|
|
|
|
|
|
2015-08-25 19:06:00 -05:00
|
|
|
|
`libphrases-hash.rlib` is the compiled crate. Before we see how to use this
|
2015-04-21 12:17:43 -05:00
|
|
|
|
crate from another crate, let’s break it up into multiple files.
|
2014-09-25 23:20:25 -05:00
|
|
|
|
|
|
|
|
|
# Multiple file crates
|
|
|
|
|
|
2015-04-21 12:17:43 -05:00
|
|
|
|
If each crate were just one file, these files would get very large. It’s often
|
2014-09-25 23:20:25 -05:00
|
|
|
|
easier to split up crates into multiple files, and Rust supports this in two
|
|
|
|
|
ways.
|
|
|
|
|
|
|
|
|
|
Instead of declaring a module like this:
|
|
|
|
|
|
2015-05-18 14:10:00 -05:00
|
|
|
|
```rust,ignore
|
2014-09-25 23:20:25 -05:00
|
|
|
|
mod english {
|
|
|
|
|
// contents of our module go here
|
|
|
|
|
}
|
|
|
|
|
```
|
|
|
|
|
|
|
|
|
|
We can instead declare our module like this:
|
|
|
|
|
|
2015-05-18 14:10:00 -05:00
|
|
|
|
```rust,ignore
|
2014-09-25 23:20:25 -05:00
|
|
|
|
mod english;
|
|
|
|
|
```
|
|
|
|
|
|
|
|
|
|
If we do that, Rust will expect to find either a `english.rs` file, or a
|
2015-03-13 22:55:01 -05:00
|
|
|
|
`english/mod.rs` file with the contents of our module.
|
2014-09-25 23:20:25 -05:00
|
|
|
|
|
2015-04-21 12:17:43 -05:00
|
|
|
|
Note that in these files, you don’t need to re-declare the module: that’s
|
2014-09-25 23:20:25 -05:00
|
|
|
|
already been done with the initial `mod` declaration.
|
|
|
|
|
|
|
|
|
|
Using these two techniques, we can break up our crate into two directories and
|
|
|
|
|
seven files:
|
|
|
|
|
|
|
|
|
|
```bash
|
|
|
|
|
$ tree .
|
|
|
|
|
.
|
|
|
|
|
├── Cargo.lock
|
|
|
|
|
├── Cargo.toml
|
|
|
|
|
├── src
|
|
|
|
|
│ ├── english
|
|
|
|
|
│ │ ├── farewells.rs
|
|
|
|
|
│ │ ├── greetings.rs
|
|
|
|
|
│ │ └── mod.rs
|
|
|
|
|
│ ├── japanese
|
|
|
|
|
│ │ ├── farewells.rs
|
|
|
|
|
│ │ ├── greetings.rs
|
|
|
|
|
│ │ └── mod.rs
|
|
|
|
|
│ └── lib.rs
|
|
|
|
|
└── target
|
2015-04-02 16:15:28 -05:00
|
|
|
|
└── debug
|
|
|
|
|
├── build
|
|
|
|
|
├── deps
|
|
|
|
|
├── examples
|
|
|
|
|
├── libphrases-a7448e02a0468eaa.rlib
|
|
|
|
|
└── native
|
2014-09-25 23:20:25 -05:00
|
|
|
|
```
|
|
|
|
|
|
|
|
|
|
`src/lib.rs` is our crate root, and looks like this:
|
|
|
|
|
|
2015-05-18 14:10:00 -05:00
|
|
|
|
```rust,ignore
|
2014-09-25 23:20:25 -05:00
|
|
|
|
mod english;
|
|
|
|
|
mod japanese;
|
|
|
|
|
```
|
|
|
|
|
|
|
|
|
|
These two declarations tell Rust to look for either `src/english.rs` and
|
|
|
|
|
`src/japanese.rs`, or `src/english/mod.rs` and `src/japanese/mod.rs`, depending
|
2015-04-21 12:17:43 -05:00
|
|
|
|
on our preference. In this case, because our modules have sub-modules, we’ve
|
2014-09-25 23:20:25 -05:00
|
|
|
|
chosen the second. Both `src/english/mod.rs` and `src/japanese/mod.rs` look
|
|
|
|
|
like this:
|
|
|
|
|
|
2015-05-18 14:10:00 -05:00
|
|
|
|
```rust,ignore
|
2014-09-25 23:20:25 -05:00
|
|
|
|
mod greetings;
|
|
|
|
|
mod farewells;
|
|
|
|
|
```
|
|
|
|
|
|
|
|
|
|
Again, these declarations tell Rust to look for either
|
|
|
|
|
`src/english/greetings.rs` and `src/japanese/greetings.rs` or
|
|
|
|
|
`src/english/farewells/mod.rs` and `src/japanese/farewells/mod.rs`. Because
|
2015-04-21 12:17:43 -05:00
|
|
|
|
these sub-modules don’t have their own sub-modules, we’ve chosen to make them
|
2014-09-25 23:20:25 -05:00
|
|
|
|
`src/english/greetings.rs` and `src/japanese/farewells.rs`. Whew!
|
|
|
|
|
|
2015-01-18 06:24:13 -06:00
|
|
|
|
The contents of `src/english/greetings.rs` and `src/japanese/farewells.rs` are
|
2015-04-21 12:17:43 -05:00
|
|
|
|
both empty at the moment. Let’s add some functions.
|
2014-09-25 23:20:25 -05:00
|
|
|
|
|
|
|
|
|
Put this in `src/english/greetings.rs`:
|
|
|
|
|
|
|
|
|
|
```rust
|
|
|
|
|
fn hello() -> String {
|
|
|
|
|
"Hello!".to_string()
|
2014-12-09 12:26:04 -06:00
|
|
|
|
}
|
2014-09-25 23:20:25 -05:00
|
|
|
|
```
|
|
|
|
|
|
|
|
|
|
Put this in `src/english/farewells.rs`:
|
|
|
|
|
|
|
|
|
|
```rust
|
|
|
|
|
fn goodbye() -> String {
|
|
|
|
|
"Goodbye.".to_string()
|
2014-12-09 12:26:04 -06:00
|
|
|
|
}
|
2014-09-25 23:20:25 -05:00
|
|
|
|
```
|
|
|
|
|
|
|
|
|
|
Put this in `src/japanese/greetings.rs`:
|
|
|
|
|
|
|
|
|
|
```rust
|
|
|
|
|
fn hello() -> String {
|
|
|
|
|
"こんにちは".to_string()
|
2014-12-09 12:26:04 -06:00
|
|
|
|
}
|
2014-09-25 23:20:25 -05:00
|
|
|
|
```
|
|
|
|
|
|
|
|
|
|
Of course, you can copy and paste this from this web page, or just type
|
2015-04-21 12:17:43 -05:00
|
|
|
|
something else. It’s not important that you actually put ‘konnichiwa’ to learn
|
2014-09-25 23:20:25 -05:00
|
|
|
|
about the module system.
|
|
|
|
|
|
|
|
|
|
Put this in `src/japanese/farewells.rs`:
|
|
|
|
|
|
|
|
|
|
```rust
|
|
|
|
|
fn goodbye() -> String {
|
|
|
|
|
"さようなら".to_string()
|
2014-12-09 12:26:04 -06:00
|
|
|
|
}
|
2014-09-25 23:20:25 -05:00
|
|
|
|
```
|
|
|
|
|
|
2015-04-21 12:17:43 -05:00
|
|
|
|
(This is ‘Sayōnara’, if you’re curious.)
|
2014-09-25 23:20:25 -05:00
|
|
|
|
|
2015-04-21 12:17:43 -05:00
|
|
|
|
Now that we have some functionality in our crate, let’s try to use it from
|
2014-09-25 23:20:25 -05:00
|
|
|
|
another crate.
|
|
|
|
|
|
|
|
|
|
# Importing External Crates
|
|
|
|
|
|
2015-04-21 12:17:43 -05:00
|
|
|
|
We have a library crate. Let’s make an executable crate that imports and uses
|
2014-09-25 23:20:25 -05:00
|
|
|
|
our library.
|
|
|
|
|
|
2015-04-21 12:17:43 -05:00
|
|
|
|
Make a `src/main.rs` and put this in it (it won’t quite compile yet):
|
2014-09-25 23:20:25 -05:00
|
|
|
|
|
|
|
|
|
```rust,ignore
|
|
|
|
|
extern crate phrases;
|
|
|
|
|
|
|
|
|
|
fn main() {
|
|
|
|
|
println!("Hello in English: {}", phrases::english::greetings::hello());
|
|
|
|
|
println!("Goodbye in English: {}", phrases::english::farewells::goodbye());
|
|
|
|
|
|
|
|
|
|
println!("Hello in Japanese: {}", phrases::japanese::greetings::hello());
|
|
|
|
|
println!("Goodbye in Japanese: {}", phrases::japanese::farewells::goodbye());
|
|
|
|
|
}
|
|
|
|
|
```
|
|
|
|
|
|
|
|
|
|
The `extern crate` declaration tells Rust that we need to compile and link to
|
2015-04-21 12:17:43 -05:00
|
|
|
|
the `phrases` crate. We can then use `phrases`’ modules in this one. As we
|
2014-09-25 23:20:25 -05:00
|
|
|
|
mentioned earlier, you can use double colons to refer to sub-modules and the
|
|
|
|
|
functions inside of them.
|
|
|
|
|
|
2015-09-05 15:42:46 -05:00
|
|
|
|
(Note: when importing a crate that has dashes in its name "like-this", which is
|
|
|
|
|
not a valid Rust identifier, it will be converted by changing the dashes to
|
|
|
|
|
underscores, so you would write `extern crate like_this;`.)
|
|
|
|
|
|
2014-09-25 23:20:25 -05:00
|
|
|
|
Also, Cargo assumes that `src/main.rs` is the crate root of a binary crate,
|
2015-01-20 19:37:39 -06:00
|
|
|
|
rather than a library crate. Our package now has two crates: `src/lib.rs` and
|
2014-09-25 23:20:25 -05:00
|
|
|
|
`src/main.rs`. This pattern is quite common for executable crates: most
|
|
|
|
|
functionality is in a library crate, and the executable crate uses that
|
2015-04-21 12:17:43 -05:00
|
|
|
|
library. This way, other programs can also use the library crate, and it’s also
|
2014-09-25 23:20:25 -05:00
|
|
|
|
a nice separation of concerns.
|
|
|
|
|
|
2015-04-21 12:17:43 -05:00
|
|
|
|
This doesn’t quite work yet, though. We get four errors that look similar to
|
2014-09-25 23:20:25 -05:00
|
|
|
|
this:
|
|
|
|
|
|
|
|
|
|
```bash
|
|
|
|
|
$ cargo build
|
|
|
|
|
Compiling phrases v0.0.1 (file:///home/you/projects/phrases)
|
2015-04-02 16:15:28 -05:00
|
|
|
|
src/main.rs:4:38: 4:72 error: function `hello` is private
|
|
|
|
|
src/main.rs:4 println!("Hello in English: {}", phrases::english::greetings::hello());
|
|
|
|
|
^~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
|
2014-09-25 23:20:25 -05:00
|
|
|
|
note: in expansion of format_args!
|
2015-04-02 16:15:28 -05:00
|
|
|
|
<std macros>:2:25: 2:58 note: expansion site
|
|
|
|
|
<std macros>:1:1: 2:62 note: in expansion of print!
|
|
|
|
|
<std macros>:3:1: 3:54 note: expansion site
|
|
|
|
|
<std macros>:1:1: 3:58 note: in expansion of println!
|
|
|
|
|
phrases/src/main.rs:4:5: 4:76 note: expansion site
|
2014-09-25 23:20:25 -05:00
|
|
|
|
```
|
|
|
|
|
|
2015-04-21 12:17:43 -05:00
|
|
|
|
By default, everything is private in Rust. Let’s talk about this in some more
|
2014-09-25 23:20:25 -05:00
|
|
|
|
depth.
|
|
|
|
|
|
|
|
|
|
# Exporting a Public Interface
|
|
|
|
|
|
|
|
|
|
Rust allows you to precisely control which aspects of your interface are
|
|
|
|
|
public, and so private is the default. To make things public, you use the `pub`
|
2015-04-21 12:17:43 -05:00
|
|
|
|
keyword. Let’s focus on the `english` module first, so let’s reduce our `src/main.rs`
|
2014-09-25 23:20:25 -05:00
|
|
|
|
to just this:
|
|
|
|
|
|
2015-05-18 14:10:00 -05:00
|
|
|
|
```rust,ignore
|
2014-09-25 23:20:25 -05:00
|
|
|
|
extern crate phrases;
|
|
|
|
|
|
|
|
|
|
fn main() {
|
|
|
|
|
println!("Hello in English: {}", phrases::english::greetings::hello());
|
|
|
|
|
println!("Goodbye in English: {}", phrases::english::farewells::goodbye());
|
|
|
|
|
}
|
|
|
|
|
```
|
|
|
|
|
|
2015-04-21 12:17:43 -05:00
|
|
|
|
In our `src/lib.rs`, let’s add `pub` to the `english` module declaration:
|
2014-09-25 23:20:25 -05:00
|
|
|
|
|
2015-05-18 14:10:00 -05:00
|
|
|
|
```rust,ignore
|
2014-09-25 23:20:25 -05:00
|
|
|
|
pub mod english;
|
|
|
|
|
mod japanese;
|
|
|
|
|
```
|
|
|
|
|
|
2015-04-21 12:17:43 -05:00
|
|
|
|
And in our `src/english/mod.rs`, let’s make both `pub`:
|
2014-09-25 23:20:25 -05:00
|
|
|
|
|
2015-05-18 14:10:00 -05:00
|
|
|
|
```rust,ignore
|
2014-09-25 23:20:25 -05:00
|
|
|
|
pub mod greetings;
|
|
|
|
|
pub mod farewells;
|
|
|
|
|
```
|
|
|
|
|
|
2015-04-21 12:17:43 -05:00
|
|
|
|
In our `src/english/greetings.rs`, let’s add `pub` to our `fn` declaration:
|
2014-09-25 23:20:25 -05:00
|
|
|
|
|
2015-05-18 14:10:00 -05:00
|
|
|
|
```rust,ignore
|
2014-09-25 23:20:25 -05:00
|
|
|
|
pub fn hello() -> String {
|
|
|
|
|
"Hello!".to_string()
|
|
|
|
|
}
|
|
|
|
|
```
|
|
|
|
|
|
|
|
|
|
And also in `src/english/farewells.rs`:
|
|
|
|
|
|
2015-05-18 14:10:00 -05:00
|
|
|
|
```rust,ignore
|
2014-09-25 23:20:25 -05:00
|
|
|
|
pub fn goodbye() -> String {
|
|
|
|
|
"Goodbye.".to_string()
|
|
|
|
|
}
|
|
|
|
|
```
|
|
|
|
|
|
|
|
|
|
Now, our crate compiles, albeit with warnings about not using the `japanese`
|
|
|
|
|
functions:
|
|
|
|
|
|
|
|
|
|
```bash
|
|
|
|
|
$ cargo run
|
|
|
|
|
Compiling phrases v0.0.1 (file:///home/you/projects/phrases)
|
2015-04-02 16:15:28 -05:00
|
|
|
|
src/japanese/greetings.rs:1:1: 3:2 warning: function is never used: `hello`, #[warn(dead_code)] on by default
|
|
|
|
|
src/japanese/greetings.rs:1 fn hello() -> String {
|
|
|
|
|
src/japanese/greetings.rs:2 "こんにちは".to_string()
|
|
|
|
|
src/japanese/greetings.rs:3 }
|
|
|
|
|
src/japanese/farewells.rs:1:1: 3:2 warning: function is never used: `goodbye`, #[warn(dead_code)] on by default
|
|
|
|
|
src/japanese/farewells.rs:1 fn goodbye() -> String {
|
|
|
|
|
src/japanese/farewells.rs:2 "さようなら".to_string()
|
|
|
|
|
src/japanese/farewells.rs:3 }
|
|
|
|
|
Running `target/debug/phrases`
|
2014-09-25 23:20:25 -05:00
|
|
|
|
Hello in English: Hello!
|
|
|
|
|
Goodbye in English: Goodbye.
|
|
|
|
|
```
|
|
|
|
|
|
2015-07-25 14:05:32 -05:00
|
|
|
|
`pub` also applies to `struct`s and their member fields. In keeping with Rust’s
|
|
|
|
|
tendency toward safety, simply making a `struct` public won't automatically
|
|
|
|
|
make its members public: you must mark the fields individually with `pub`.
|
|
|
|
|
|
2014-09-25 23:20:25 -05:00
|
|
|
|
Now that our functions are public, we can use them. Great! However, typing out
|
|
|
|
|
`phrases::english::greetings::hello()` is very long and repetitive. Rust has
|
|
|
|
|
another keyword for importing names into the current scope, so that you can
|
2015-04-21 12:17:43 -05:00
|
|
|
|
refer to them with shorter names. Let’s talk about `use`.
|
2014-09-25 23:20:25 -05:00
|
|
|
|
|
|
|
|
|
# Importing Modules with `use`
|
|
|
|
|
|
|
|
|
|
Rust has a `use` keyword, which allows us to import names into our local scope.
|
2015-04-21 12:17:43 -05:00
|
|
|
|
Let’s change our `src/main.rs` to look like this:
|
2014-09-25 23:20:25 -05:00
|
|
|
|
|
2015-05-18 14:10:00 -05:00
|
|
|
|
```rust,ignore
|
2014-09-25 23:20:25 -05:00
|
|
|
|
extern crate phrases;
|
|
|
|
|
|
|
|
|
|
use phrases::english::greetings;
|
|
|
|
|
use phrases::english::farewells;
|
|
|
|
|
|
|
|
|
|
fn main() {
|
|
|
|
|
println!("Hello in English: {}", greetings::hello());
|
|
|
|
|
println!("Goodbye in English: {}", farewells::goodbye());
|
|
|
|
|
}
|
|
|
|
|
```
|
|
|
|
|
|
|
|
|
|
The two `use` lines import each module into the local scope, so we can refer to
|
2015-04-21 12:17:43 -05:00
|
|
|
|
the functions by a much shorter name. By convention, when importing functions, it’s
|
2014-09-25 23:20:25 -05:00
|
|
|
|
considered best practice to import the module, rather than the function directly. In
|
|
|
|
|
other words, you _can_ do this:
|
|
|
|
|
|
2015-05-18 14:10:00 -05:00
|
|
|
|
```rust,ignore
|
2014-09-25 23:20:25 -05:00
|
|
|
|
extern crate phrases;
|
|
|
|
|
|
|
|
|
|
use phrases::english::greetings::hello;
|
|
|
|
|
use phrases::english::farewells::goodbye;
|
|
|
|
|
|
|
|
|
|
fn main() {
|
|
|
|
|
println!("Hello in English: {}", hello());
|
|
|
|
|
println!("Goodbye in English: {}", goodbye());
|
|
|
|
|
}
|
|
|
|
|
```
|
|
|
|
|
|
2015-03-01 22:45:53 -06:00
|
|
|
|
But it is not idiomatic. This is significantly more likely to introduce a
|
2015-04-21 12:17:43 -05:00
|
|
|
|
naming conflict. In our short program, it’s not a big deal, but as it grows, it
|
2014-09-25 23:20:25 -05:00
|
|
|
|
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
|
|
|
|
|
this:
|
|
|
|
|
|
2015-05-18 14:10:00 -05:00
|
|
|
|
```rust,ignore
|
2014-09-25 23:20:25 -05:00
|
|
|
|
extern crate phrases;
|
|
|
|
|
|
|
|
|
|
use phrases::english::greetings::hello;
|
|
|
|
|
use phrases::japanese::greetings::hello;
|
|
|
|
|
|
|
|
|
|
fn main() {
|
|
|
|
|
println!("Hello in English: {}", hello());
|
|
|
|
|
println!("Hello in Japanese: {}", hello());
|
|
|
|
|
}
|
|
|
|
|
```
|
|
|
|
|
|
|
|
|
|
Rust will give us a compile-time error:
|
|
|
|
|
|
2014-12-10 14:12:16 -06:00
|
|
|
|
```text
|
2014-09-25 23:20:25 -05:00
|
|
|
|
Compiling phrases v0.0.1 (file:///home/you/projects/phrases)
|
2015-04-02 16:15:28 -05:00
|
|
|
|
src/main.rs:4:5: 4:40 error: a value named `hello` has already been imported in this module [E0252]
|
|
|
|
|
src/main.rs:4 use phrases::japanese::greetings::hello;
|
|
|
|
|
^~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
|
2014-09-25 23:20:25 -05:00
|
|
|
|
error: aborting due to previous error
|
|
|
|
|
Could not compile `phrases`.
|
|
|
|
|
```
|
|
|
|
|
|
2015-04-21 12:17:43 -05:00
|
|
|
|
If we’re importing multiple names from the same module, we don’t have to type it out
|
2015-03-13 22:55:01 -05:00
|
|
|
|
twice. Instead of this:
|
2014-09-25 23:20:25 -05:00
|
|
|
|
|
2015-05-18 14:10:00 -05:00
|
|
|
|
```rust,ignore
|
2014-09-25 23:20:25 -05:00
|
|
|
|
use phrases::english::greetings;
|
|
|
|
|
use phrases::english::farewells;
|
|
|
|
|
```
|
|
|
|
|
|
2015-03-13 22:55:01 -05:00
|
|
|
|
We can use this shortcut:
|
2014-09-25 23:20:25 -05:00
|
|
|
|
|
2015-05-18 14:10:00 -05:00
|
|
|
|
```rust,ignore
|
2014-09-25 23:20:25 -05:00
|
|
|
|
use phrases::english::{greetings, farewells};
|
|
|
|
|
```
|
|
|
|
|
|
|
|
|
|
## Re-exporting with `pub use`
|
|
|
|
|
|
2015-04-21 12:17:43 -05:00
|
|
|
|
You don’t just use `use` to shorten identifiers. You can also use it inside of your crate
|
2014-09-25 23:20:25 -05:00
|
|
|
|
to re-export a function inside another module. This allows you to present an external
|
|
|
|
|
interface that may not directly map to your internal code organization.
|
|
|
|
|
|
2015-04-21 12:17:43 -05:00
|
|
|
|
Let’s look at an example. Modify your `src/main.rs` to read like this:
|
2014-09-25 23:20:25 -05:00
|
|
|
|
|
2015-05-18 14:10:00 -05:00
|
|
|
|
```rust,ignore
|
2014-09-25 23:20:25 -05:00
|
|
|
|
extern crate phrases;
|
|
|
|
|
|
|
|
|
|
use phrases::english::{greetings,farewells};
|
|
|
|
|
use phrases::japanese;
|
|
|
|
|
|
|
|
|
|
fn main() {
|
|
|
|
|
println!("Hello in English: {}", greetings::hello());
|
|
|
|
|
println!("Goodbye in English: {}", farewells::goodbye());
|
|
|
|
|
|
|
|
|
|
println!("Hello in Japanese: {}", japanese::hello());
|
|
|
|
|
println!("Goodbye in Japanese: {}", japanese::goodbye());
|
|
|
|
|
}
|
|
|
|
|
```
|
|
|
|
|
|
|
|
|
|
Then, modify your `src/lib.rs` to make the `japanese` mod public:
|
|
|
|
|
|
2015-05-18 14:10:00 -05:00
|
|
|
|
```rust,ignore
|
2014-09-25 23:20:25 -05:00
|
|
|
|
pub mod english;
|
|
|
|
|
pub mod japanese;
|
|
|
|
|
```
|
|
|
|
|
|
|
|
|
|
Next, make the two functions public, first in `src/japanese/greetings.rs`:
|
|
|
|
|
|
2015-05-18 14:10:00 -05:00
|
|
|
|
```rust,ignore
|
2014-09-25 23:20:25 -05:00
|
|
|
|
pub fn hello() -> String {
|
|
|
|
|
"こんにちは".to_string()
|
|
|
|
|
}
|
|
|
|
|
```
|
|
|
|
|
|
|
|
|
|
And then in `src/japanese/farewells.rs`:
|
|
|
|
|
|
2015-05-18 14:10:00 -05:00
|
|
|
|
```rust,ignore
|
2014-09-25 23:20:25 -05:00
|
|
|
|
pub fn goodbye() -> String {
|
|
|
|
|
"さようなら".to_string()
|
|
|
|
|
}
|
|
|
|
|
```
|
|
|
|
|
|
|
|
|
|
Finally, modify your `src/japanese/mod.rs` to read like this:
|
|
|
|
|
|
2015-05-18 14:10:00 -05:00
|
|
|
|
```rust,ignore
|
2014-09-25 23:20:25 -05:00
|
|
|
|
pub use self::greetings::hello;
|
|
|
|
|
pub use self::farewells::goodbye;
|
|
|
|
|
|
|
|
|
|
mod greetings;
|
|
|
|
|
mod farewells;
|
|
|
|
|
```
|
|
|
|
|
|
|
|
|
|
The `pub use` declaration brings the function into scope at this part of our
|
2015-04-21 12:17:43 -05:00
|
|
|
|
module hierarchy. Because we’ve `pub use`d this inside of our `japanese`
|
2014-09-25 23:20:25 -05:00
|
|
|
|
module, we now have a `phrases::japanese::hello()` function and a
|
|
|
|
|
`phrases::japanese::goodbye()` function, even though the code for them lives in
|
|
|
|
|
`phrases::japanese::greetings::hello()` and
|
2015-04-21 12:17:43 -05:00
|
|
|
|
`phrases::japanese::farewells::goodbye()`. Our internal organization doesn’t
|
2014-09-25 23:20:25 -05:00
|
|
|
|
define our external interface.
|
|
|
|
|
|
2015-03-14 18:09:26 -05:00
|
|
|
|
Here we have a `pub use` for each function we want to bring into the
|
2015-01-24 20:57:45 -06:00
|
|
|
|
`japanese` scope. We could alternatively use the wildcard syntax to include
|
2015-03-14 18:09:26 -05:00
|
|
|
|
everything from `greetings` into the current scope: `pub use self::greetings::*`.
|
2015-01-24 20:57:45 -06:00
|
|
|
|
|
2015-03-08 12:58:14 -05:00
|
|
|
|
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
|
2015-04-21 12:17:43 -05:00
|
|
|
|
place in the hierarchy instead. There’s one more special form of `use`: you can
|
2015-03-08 12:58:14 -05:00
|
|
|
|
`use super::` to reach one level up the tree from your current location. Some
|
2015-04-21 12:17:43 -05:00
|
|
|
|
people like to think of `self` as `.` and `super` as `..`, from many shells’
|
2015-03-08 12:58:14 -05:00
|
|
|
|
display for the current directory and the parent directory.
|
|
|
|
|
|
2015-03-18 19:24:22 -05:00
|
|
|
|
Outside of `use`, paths are relative: `foo::bar()` refers to a function inside
|
2015-04-21 12:17:43 -05:00
|
|
|
|
of `foo` relative to where we are. If that’s prefixed with `::`, as in
|
2015-03-18 19:24:22 -05:00
|
|
|
|
`::foo::bar()`, it refers to a different `foo`, an absolute path from your
|
|
|
|
|
crate root.
|
|
|
|
|
|
2014-09-25 23:20:25 -05:00
|
|
|
|
This will build and run:
|
|
|
|
|
|
|
|
|
|
```bash
|
2015-01-11 02:40:42 -06:00
|
|
|
|
$ cargo run
|
2014-09-25 23:20:25 -05:00
|
|
|
|
Compiling phrases v0.0.1 (file:///home/you/projects/phrases)
|
2015-04-02 16:15:28 -05:00
|
|
|
|
Running `target/debug/phrases`
|
2014-09-25 23:20:25 -05:00
|
|
|
|
Hello in English: Hello!
|
|
|
|
|
Goodbye in English: Goodbye.
|
|
|
|
|
Hello in Japanese: こんにちは
|
|
|
|
|
Goodbye in Japanese: さようなら
|
|
|
|
|
```
|
2015-09-04 22:08:53 -05:00
|
|
|
|
|
|
|
|
|
## Complex imports
|
|
|
|
|
|
|
|
|
|
Rust offers several advanced options that can add compactness and
|
|
|
|
|
convenience to your `extern crate` and `use` statements. Here is an example:
|
|
|
|
|
|
|
|
|
|
```rust,ignore
|
|
|
|
|
extern crate phrases as sayings;
|
|
|
|
|
|
|
|
|
|
use sayings::japanese::greetings as ja_greetings;
|
|
|
|
|
use sayings::japanese::farewells::*;
|
|
|
|
|
use sayings::english::{self, greetings as en_greetings, farewells as en_farewells};
|
|
|
|
|
|
|
|
|
|
fn main() {
|
|
|
|
|
println!("Hello in English; {}", en_greetings::hello());
|
|
|
|
|
println!("And in Japanese: {}", ja_greetings::hello());
|
|
|
|
|
println!("Goodbye in English: {}", english::farewells::goodbye());
|
|
|
|
|
println!("Again: {}", en_farewells::goodbye());
|
|
|
|
|
println!("And in Japanese: {}", goodbye());
|
|
|
|
|
}
|
|
|
|
|
```
|
|
|
|
|
|
|
|
|
|
What's going on here?
|
|
|
|
|
|
|
|
|
|
First, both `extern crate` and `use` allow renaming the thing that is being
|
|
|
|
|
imported. So the crate is still called "phrases", but here we will refer
|
|
|
|
|
to it as "sayings". Similarly, the first `use` statement pulls in the
|
2015-10-04 15:17:35 -05:00
|
|
|
|
`japanese::greetings` module from the crate, but makes it available as
|
|
|
|
|
`ja_greetings` as opposed to simply `greetings`. This can help to avoid
|
2015-09-04 22:08:53 -05:00
|
|
|
|
ambiguity when importing similarly-named items from different places.
|
|
|
|
|
|
|
|
|
|
The second `use` statement uses a star glob to bring in _all_ symbols from the
|
|
|
|
|
`sayings::japanese::farewells` module. As you can see we can later refer to
|
|
|
|
|
the Japanese `goodbye` function with no module qualifiers. This kind of glob
|
|
|
|
|
should be used sparingly.
|
|
|
|
|
|
|
|
|
|
The third `use` statement bears more explanation. It's using "brace expansion"
|
|
|
|
|
globbing to compress three `use` statements into one (this sort of syntax
|
|
|
|
|
may be familiar if you've written Linux shell scripts before). The
|
|
|
|
|
uncompressed form of this statement would be:
|
2015-10-06 00:11:18 -05:00
|
|
|
|
|
2015-09-04 22:08:53 -05:00
|
|
|
|
```rust,ignore
|
|
|
|
|
use sayings::english;
|
|
|
|
|
use sayings::english::greetings as en_greetings;
|
|
|
|
|
use sayings::english::farewells as en_farewells;
|
|
|
|
|
```
|
2015-10-06 00:11:18 -05:00
|
|
|
|
|
2015-09-04 22:08:53 -05:00
|
|
|
|
As you can see, the curly brackets compress `use` statements for several items
|
|
|
|
|
under the same path, and in this context `self` just refers back to that path.
|
|
|
|
|
Note: The curly brackets cannot be nested or mixed with star globbing.
|