Remove much of the modules section.

This part can get _really_ confusing, and we want to make sure that
people succeed in the guide. I plan on making a module guide in the
future to replace the information here.
This commit is contained in:
Steve Klabnik 2014-09-10 18:28:37 -04:00
parent 9c8c82b87d
commit 311227003f

View File

@ -2751,197 +2751,8 @@ $ cargo run
Hello, world!
```
Nice!
There's a common pattern when you're building an executable: you build both an
executable and a library, and put most of your logic in the library. That way,
other programs can use that library to build their own functionality.
Let's do that with our project. If you remember, libraries and executables
are both crates, so while our project has one crate now, let's make a second:
one for the library, and one for the executable.
To make the second crate, open up `src/lib.rs` and put this code in it:
```{rust}
mod hello {
pub fn print_hello() {
println!("Hello, world!");
}
}
```
And change your `src/main.rs` to look like this:
```{rust,ignore}
extern crate modules;
fn main() {
modules::hello::print_hello();
}
```
There's been a few changes. First, we moved our `hello` module into its own
file, `src/lib.rs`. This is the file that Cargo expects a library crate to
be named, by convention.
Next, we added an `extern crate modules` to the top of our `src/main.rs`. This,
as you can guess, lets Rust know that our crate relies on another, external
crate. We also had to modify our call to `print_hello`: now that it's in
another crate, we need to specify that crate first.
This doesn't _quite_ work yet. Try it:
```{notrust,ignore}
$ cargo build
Compiling modules v0.0.1 (file:///home/you/projects/modules)
/home/you/projects/modules/src/lib.rs:2:5: 4:6 warning: code is never used: `print_hello`, #[warn(dead_code)] on by default
/home/you/projects/modules/src/lib.rs:2 pub fn print_hello() {
/home/you/projects/modules/src/lib.rs:3 println!("Hello, world!");
/home/you/projects/modules/src/lib.rs:4 }
/home/you/projects/modules/src/main.rs:4:5: 4:32 error: function `print_hello` is private
/home/you/projects/modules/src/main.rs:4 modules::hello::print_hello();
^~~~~~~~~~~~~~~~~~~~~~~~~~~
error: aborting due to previous error
Could not compile `modules`.
```
First, we get a warning that some code is never used. Odd. Next, we get an error:
`print_hello` is private, so we can't call it. Notice that the first error came
from `src/lib.rs`, and the second came from `src/main.rs`: cargo is smart enough
to build it all with one command. Also, after seeing the second error, the warning
makes sense: we never actually call `hello_world`, because we're not allowed to!
Just like modules, crates also have private visibility by default. Any modules
inside of a crate can only be used by other modules in the crate, unless they
use `pub`. In `src/lib.rs`, change this line:
```{rust,ignore}
mod hello {
```
To this:
```{rust,ignore}
pub mod hello {
```
And everything should work:
```{notrust,ignore}
$ cargo run
Compiling modules v0.0.1 (file:///home/you/projects/modules)
Running `target/modules`
Hello, world!
```
Let's do one more thing: add a `goodbye` module as well. Imagine a `src/lib.rs`
that looks like this:
```{rust,ignore}
pub mod hello {
pub fn print_hello() {
println!("Hello, world!");
}
}
pub mod goodbye {
pub fn print_goodbye() {
println!("Goodbye for now!");
}
}
```
Now, these two modules are pretty small, but imagine we've written a real, large
program: they could both be huge. So maybe we want to move them into their own
files. We can do that pretty easily, and there are two different conventions
for doing it. Let's give each a try. First, make `src/lib.rs` look like this:
```{rust,ignore}
pub mod hello;
pub mod goodbye;
```
This tells Rust that this crate has two public modules: `hello` and `goodbye`.
Next, make a `src/hello.rs` that contains this:
```{rust,ignore}
pub fn print_hello() {
println!("Hello, world!");
}
```
When we include a module like this, we don't need to make the `mod` declaration
in `hello.rs`, because it's already been declared in `lib.rs`. `hello.rs` just
contains the body of the module which is defined (by the `pub mod hello`) in
`lib.rs`. This helps prevent 'rightward drift': when you end up indenting so
many times that your code is hard to read.
Finally, make a new directory, `src/goodbye`, and make a new file in it,
`src/goodbye/mod.rs`:
```{rust,ignore}
pub fn print_goodbye() {
println!("Bye for now!");
}
```
Same deal, but we can make a folder with a `mod.rs` instead of `mod_name.rs` in
the same directory. If you have a lot of modules, nested folders can make
sense. For example, if the `goodbye` module had its _own_ modules inside of
it, putting all of that in a folder helps keep our directory structure tidy.
And in fact, if you place the modules in separate files, they're required to be
in separate folders.
This should all compile as usual:
```{notrust,ignore}
$ cargo build
Compiling modules v0.0.1 (file:///home/you/projects/modules)
```
We've seen how the `::` operator can be used to call into modules, but when
we have deep nesting like `modules::hello::say_hello`, it can get tedious.
That's why we have the `use` keyword.
`use` allows us to bring certain names into another scope. For example, here's
our main program:
```{rust,ignore}
extern crate modules;
fn main() {
modules::hello::print_hello();
}
```
We could instead write this:
```{rust,ignore}
extern crate modules;
use modules::hello::print_hello;
fn main() {
print_hello();
}
```
By bringing `print_hello` into scope, we don't need to qualify it anymore. However,
it's considered proper style to do write this code like like this:
```{rust,ignore}
extern crate modules;
use modules::hello;
fn main() {
hello::print_hello();
}
```
By just bringing the module into scope, we can keep one level of namespacing.
Nice! There are more things we can do with modules, including moving them into
their own files. This is enough detail for now.
# Testing