diff options
Diffstat (limited to 'src/doc/book/src/ch07-04-bringing-paths-into-scope-with-the-use-keyword.md')
-rw-r--r-- | src/doc/book/src/ch07-04-bringing-paths-into-scope-with-the-use-keyword.md | 309 |
1 files changed, 309 insertions, 0 deletions
diff --git a/src/doc/book/src/ch07-04-bringing-paths-into-scope-with-the-use-keyword.md b/src/doc/book/src/ch07-04-bringing-paths-into-scope-with-the-use-keyword.md new file mode 100644 index 000000000..921e5cecc --- /dev/null +++ b/src/doc/book/src/ch07-04-bringing-paths-into-scope-with-the-use-keyword.md @@ -0,0 +1,309 @@ +## Bringing Paths into Scope with the `use` Keyword + +Having to write out the paths to call functions can feel inconvenient and +repetitive. In Listing 7-7, whether we chose the absolute or relative path to +the `add_to_waitlist` function, every time we wanted to call `add_to_waitlist` +we had to specify `front_of_house` and `hosting` too. Fortunately, there’s a +way to simplify this process: we can create a shortcut to a path with the `use` +keyword once, and then use the shorter name everywhere else in the scope. + +In Listing 7-11, we bring the `crate::front_of_house::hosting` module into the +scope of the `eat_at_restaurant` function so we only have to specify +`hosting::add_to_waitlist` to call the `add_to_waitlist` function in +`eat_at_restaurant`. + +<span class="filename">Filename: src/lib.rs</span> + +```rust,noplayground,test_harness +{{#rustdoc_include ../listings/ch07-managing-growing-projects/listing-07-11/src/lib.rs}} +``` + +<span class="caption">Listing 7-11: Bringing a module into scope with +`use`</span> + +Adding `use` and a path in a scope is similar to creating a symbolic link in +the filesystem. By adding `use crate::front_of_house::hosting` in the crate +root, `hosting` is now a valid name in that scope, just as though the `hosting` +module had been defined in the crate root. Paths brought into scope with `use` +also check privacy, like any other paths. + +Note that `use` only creates the shortcut for the particular scope in which the +`use` occurs. Listing 7-12 moves the `eat_at_restaurant` function into a new +child module named `customer`, which is then a different scope than the `use` +statement, so the function body won’t compile: + +<span class="filename">Filename: src/lib.rs</span> + +```rust,noplayground,test_harness,does_not_compile,ignore +{{#rustdoc_include ../listings/ch07-managing-growing-projects/listing-07-12/src/lib.rs}} +``` + +<span class="caption">Listing 7-12: A `use` statement only applies in the scope +it’s in</span> + +The compiler error shows that the shortcut no longer applies within the +`customer` module: + +```console +{{#include ../listings/ch07-managing-growing-projects/listing-07-12/output.txt}} +``` + +Notice there’s also a warning that the `use` is no longer used in its scope! To +fix this problem, move the `use` within the `customer` module too, or reference +the shortcut in the parent module with `super::hosting` within the child +`customer` module. + +### Creating Idiomatic `use` Paths + +In Listing 7-11, you might have wondered why we specified `use +crate::front_of_house::hosting` and then called `hosting::add_to_waitlist` in +`eat_at_restaurant` rather than specifying the `use` path all the way out to +the `add_to_waitlist` function to achieve the same result, as in Listing 7-13. + +<span class="filename">Filename: src/lib.rs</span> + +```rust,noplayground,test_harness +{{#rustdoc_include ../listings/ch07-managing-growing-projects/listing-07-13/src/lib.rs}} +``` + +<span class="caption">Listing 7-13: Bringing the `add_to_waitlist` function +into scope with `use`, which is unidiomatic</span> + +Although both Listing 7-11 and 7-13 accomplish the same task, Listing 7-11 is +the idiomatic way to bring a function into scope with `use`. Bringing the +function’s parent module into scope with `use` means we have to specify the +parent module when calling the function. Specifying the parent module when +calling the function makes it clear that the function isn’t locally defined +while still minimizing repetition of the full path. The code in Listing 7-13 is +unclear as to where `add_to_waitlist` is defined. + +On the other hand, when bringing in structs, enums, and other items with `use`, +it’s idiomatic to specify the full path. Listing 7-14 shows the idiomatic way +to bring the standard library’s `HashMap` struct into the scope of a binary +crate. + +<span class="filename">Filename: src/main.rs</span> + +```rust +{{#rustdoc_include ../listings/ch07-managing-growing-projects/listing-07-14/src/main.rs}} +``` + +<span class="caption">Listing 7-14: Bringing `HashMap` into scope in an +idiomatic way</span> + +There’s no strong reason behind this idiom: it’s just the convention that has +emerged, and folks have gotten used to reading and writing Rust code this way. + +The exception to this idiom is if we’re bringing two items with the same name +into scope with `use` statements, because Rust doesn’t allow that. Listing 7-15 +shows how to bring two `Result` types into scope that have the same name but +different parent modules and how to refer to them. + +<span class="filename">Filename: src/lib.rs</span> + +```rust,noplayground +{{#rustdoc_include ../listings/ch07-managing-growing-projects/listing-07-15/src/lib.rs:here}} +``` + +<span class="caption">Listing 7-15: Bringing two types with the same name into +the same scope requires using their parent modules.</span> + +As you can see, using the parent modules distinguishes the two `Result` types. +If instead we specified `use std::fmt::Result` and `use std::io::Result`, we’d +have two `Result` types in the same scope and Rust wouldn’t know which one we +meant when we used `Result`. + +### Providing New Names with the `as` Keyword + +There’s another solution to the problem of bringing two types of the same name +into the same scope with `use`: after the path, we can specify `as` and a new +local name, or *alias*, for the type. Listing 7-16 shows another way to write +the code in Listing 7-15 by renaming one of the two `Result` types using `as`. + +<span class="filename">Filename: src/lib.rs</span> + +```rust,noplayground +{{#rustdoc_include ../listings/ch07-managing-growing-projects/listing-07-16/src/lib.rs:here}} +``` + +<span class="caption">Listing 7-16: Renaming a type when it’s brought into +scope with the `as` keyword</span> + +In the second `use` statement, we chose the new name `IoResult` for the +`std::io::Result` type, which won’t conflict with the `Result` from `std::fmt` +that we’ve also brought into scope. Listing 7-15 and Listing 7-16 are +considered idiomatic, so the choice is up to you! + +### Re-exporting Names with `pub use` + +When we bring a name into scope with the `use` keyword, the name available in +the new scope is private. To enable the code that calls our code to refer to +that name as if it had been defined in that code’s scope, we can combine `pub` +and `use`. This technique is called *re-exporting* because we’re bringing +an item into scope but also making that item available for others to bring into +their scope. + +Listing 7-17 shows the code in Listing 7-11 with `use` in the root module +changed to `pub use`. + +<span class="filename">Filename: src/lib.rs</span> + +```rust,noplayground,test_harness +{{#rustdoc_include ../listings/ch07-managing-growing-projects/listing-07-17/src/lib.rs}} +``` + +<span class="caption">Listing 7-17: Making a name available for any code to use +from a new scope with `pub use`</span> + +Before this change, external code would have to call the `add_to_waitlist` +function by using the path +`restaurant::front_of_house::hosting::add_to_waitlist()`. Now that this `pub +use` has re-exported the `hosting` module from the root module, external code +can now use the path `restaurant::hosting::add_to_waitlist()` instead. + +Re-exporting is useful when the internal structure of your code is different +from how programmers calling your code would think about the domain. For +example, in this restaurant metaphor, the people running the restaurant think +about “front of house” and “back of house.” But customers visiting a restaurant +probably won’t think about the parts of the restaurant in those terms. With +`pub use`, we can write our code with one structure but expose a different +structure. Doing so makes our library well organized for programmers working on +the library and programmers calling the library. We’ll look at another example +of `pub use` and how it affects your crate’s documentation in the [“Exporting a +Convenient Public API with `pub use`”][ch14-pub-use]<!-- ignore --> section of +Chapter 14. + +### Using External Packages + +In Chapter 2, we programmed a guessing game project that used an external +package called `rand` to get random numbers. To use `rand` in our project, we +added this line to *Cargo.toml*: + +<!-- When updating the version of `rand` used, also update the version of +`rand` used in these files so they all match: +* ch02-00-guessing-game-tutorial.md +* ch14-03-cargo-workspaces.md +--> + +<span class="filename">Filename: Cargo.toml</span> + +```toml +{{#include ../listings/ch02-guessing-game-tutorial/listing-02-02/Cargo.toml:9:}} +``` + +Adding `rand` as a dependency in *Cargo.toml* tells Cargo to download the +`rand` package and any dependencies from [crates.io](https://crates.io/) and +make `rand` available to our project. + +Then, to bring `rand` definitions into the scope of our package, we added a +`use` line starting with the name of the crate, `rand`, and listed the items +we wanted to bring into scope. Recall that in the [“Generating a Random +Number”][rand]<!-- ignore --> section in Chapter 2, we brought the `Rng` trait +into scope and called the `rand::thread_rng` function: + +```rust,ignore +{{#rustdoc_include ../listings/ch02-guessing-game-tutorial/listing-02-03/src/main.rs:ch07-04}} +``` + +Members of the Rust community have made many packages available at +[crates.io](https://crates.io/), and pulling any of them into your package +involves these same steps: listing them in your package’s *Cargo.toml* file and +using `use` to bring items from their crates into scope. + +Note that the standard `std` library is also a crate that’s external to our +package. Because the standard library is shipped with the Rust language, we +don’t need to change *Cargo.toml* to include `std`. But we do need to refer to +it with `use` to bring items from there into our package’s scope. For example, +with `HashMap` we would use this line: + +```rust +use std::collections::HashMap; +``` + +This is an absolute path starting with `std`, the name of the standard library +crate. + +### Using Nested Paths to Clean Up Large `use` Lists + +If we’re using multiple items defined in the same crate or same module, +listing each item on its own line can take up a lot of vertical space in our +files. For example, these two `use` statements we had in the Guessing Game in +Listing 2-4 bring items from `std` into scope: + +<span class="filename">Filename: src/main.rs</span> + +```rust,ignore +{{#rustdoc_include ../listings/ch07-managing-growing-projects/no-listing-01-use-std-unnested/src/main.rs:here}} +``` + +Instead, we can use nested paths to bring the same items into scope in one +line. We do this by specifying the common part of the path, followed by two +colons, and then curly brackets around a list of the parts of the paths that +differ, as shown in Listing 7-18. + +<span class="filename">Filename: src/main.rs</span> + +```rust,ignore +{{#rustdoc_include ../listings/ch07-managing-growing-projects/listing-07-18/src/main.rs:here}} +``` + +<span class="caption">Listing 7-18: Specifying a nested path to bring multiple +items with the same prefix into scope</span> + +In bigger programs, bringing many items into scope from the same crate or +module using nested paths can reduce the number of separate `use` statements +needed by a lot! + +We can use a nested path at any level in a path, which is useful when combining +two `use` statements that share a subpath. For example, Listing 7-19 shows two +`use` statements: one that brings `std::io` into scope and one that brings +`std::io::Write` into scope. + +<span class="filename">Filename: src/lib.rs</span> + +```rust,noplayground +{{#rustdoc_include ../listings/ch07-managing-growing-projects/listing-07-19/src/lib.rs}} +``` + +<span class="caption">Listing 7-19: Two `use` statements where one is a subpath +of the other</span> + +The common part of these two paths is `std::io`, and that’s the complete first +path. To merge these two paths into one `use` statement, we can use `self` in +the nested path, as shown in Listing 7-20. + +<span class="filename">Filename: src/lib.rs</span> + +```rust,noplayground +{{#rustdoc_include ../listings/ch07-managing-growing-projects/listing-07-20/src/lib.rs}} +``` + +<span class="caption">Listing 7-20: Combining the paths in Listing 7-19 into +one `use` statement</span> + +This line brings `std::io` and `std::io::Write` into scope. + +### The Glob Operator + +If we want to bring *all* public items defined in a path into scope, we can +specify that path followed by the `*` glob operator: + +```rust +use std::collections::*; +``` + +This `use` statement brings all public items defined in `std::collections` into +the current scope. Be careful when using the glob operator! Glob can make it +harder to tell what names are in scope and where a name used in your program +was defined. + +The glob operator is often used when testing to bring everything under test +into the `tests` module; we’ll talk about that in the [“How to Write +Tests”][writing-tests]<!-- ignore --> section in Chapter 11. The glob operator +is also sometimes used as part of the prelude pattern: see [the standard +library documentation](../std/prelude/index.html#other-preludes)<!-- ignore --> +for more information on that pattern. + +[ch14-pub-use]: ch14-02-publishing-to-crates-io.html#exporting-a-convenient-public-api-with-pub-use +[rand]: ch02-00-guessing-game-tutorial.html#generating-a-random-number +[writing-tests]: ch11-01-writing-tests.html#how-to-write-tests |