Files
docs-rust/ch07/ch07-04-bringing-paths-into-scope-with-the-use-keyword.html
2026-06-22 21:27:36 +05:30

402 lines
22 KiB
HTML
Raw Permalink Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>Bringing Paths Into Scope with the use Keyword</title>
</head>
<body>
<h2 id="bringing-paths-into-scope-with-the-use-keyword"><a class="header" href="#bringing-paths-into-scope-with-the-use-keyword">Bringing Paths into Scope with the <code>use</code> Keyword</a></h2>
<p>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 <code>add_to_waitlist</code> function, every time we wanted to call <code>add_to_waitlist</code>
we had to specify <code>front_of_house</code> and <code>hosting</code> too. Fortunately, theres a
way to simplify this process: We can create a shortcut to a path with the <code>use</code>
keyword once and then use the shorter name everywhere else in the scope.</p>
<p>In Listing 7-11, we bring the <code>crate::front_of_house::hosting</code> module into the
scope of the <code>eat_at_restaurant</code> function so that we only have to specify
<code>hosting::add_to_waitlist</code> to call the <code>add_to_waitlist</code> function in
<code>eat_at_restaurant</code>.</p>
<figure class="listing" id="listing-7-11">
<span class="file-name">Filename: src/lib.rs</span>
<pre><code class="language-rust noplayground test_harness">mod front_of_house {
pub mod hosting {
pub fn add_to_waitlist() {}
}
}
use crate::front_of_house::hosting;
pub fn eat_at_restaurant() {
hosting::add_to_waitlist();
}</code></pre>
<figcaption><a href="#listing-7-11">Listing 7-11</a>: Bringing a module into scope with <code>use</code></figcaption>
</figure>
<p>Adding <code>use</code> and a path in a scope is similar to creating a symbolic link in
the filesystem. By adding <code>use crate::front_of_house::hosting</code> in the crate
root, <code>hosting</code> is now a valid name in that scope, just as though the <code>hosting</code>
module had been defined in the crate root. Paths brought into scope with <code>use</code>
also check privacy, like any other paths.</p>
<p>Note that <code>use</code> only creates the shortcut for the particular scope in which the
<code>use</code> occurs. Listing 7-12 moves the <code>eat_at_restaurant</code> function into a new
child module named <code>customer</code>, which is then a different scope than the <code>use</code>
statement, so the function body wont compile.</p>
<figure class="listing" id="listing-7-12">
<span class="file-name">Filename: src/lib.rs</span>
<pre><code class="language-rust noplayground test_harness does_not_compile ignore">mod front_of_house {
pub mod hosting {
pub fn add_to_waitlist() {}
}
}
use crate::front_of_house::hosting;
mod customer {
pub fn eat_at_restaurant() {
hosting::add_to_waitlist();
}
}</code></pre>
<figcaption><a href="#listing-7-12">Listing 7-12</a>: A <code>use</code> statement only applies in the scope its in.</figcaption>
</figure>
<p>The compiler error shows that the shortcut no longer applies within the
<code>customer</code> module:</p>
<pre><code class="language-console">$ cargo build
Compiling restaurant v0.1.0 (file:///projects/restaurant)
error[E0433]: failed to resolve: use of unresolved module or unlinked crate `hosting`
--&gt; src/lib.rs:11:9
|
11 | hosting::add_to_waitlist();
| ^^^^^^^ use of unresolved module or unlinked crate `hosting`
|
= help: if you wanted to use a crate named `hosting`, use `cargo add hosting` to add it to your `Cargo.toml`
help: consider importing this module through its public re-export
|
10 + use crate::hosting;
|
warning: unused import: `crate::front_of_house::hosting`
--&gt; src/lib.rs:7:5
|
7 | use crate::front_of_house::hosting;
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
|
= note: `#[warn(unused_imports)]` on by default
For more information about this error, try `rustc --explain E0433`.
warning: `restaurant` (lib) generated 1 warning
error: could not compile `restaurant` (lib) due to 1 previous error; 1 warning emitted
</code></pre>
<p>Notice theres also a warning that the <code>use</code> is no longer used in its scope! To
fix this problem, move the <code>use</code> within the <code>customer</code> module too, or reference
the shortcut in the parent module with <code>super::hosting</code> within the child
<code>customer</code> module.</p>
<h3 id="creating-idiomatic-use-paths"><a class="header" href="#creating-idiomatic-use-paths">Creating Idiomatic <code>use</code> Paths</a></h3>
<p>In Listing 7-11, you might have wondered why we specified <code>use crate::front_of_house::hosting</code> and then called <code>hosting::add_to_waitlist</code> in
<code>eat_at_restaurant</code>, rather than specifying the <code>use</code> path all the way out to
the <code>add_to_waitlist</code> function to achieve the same result, as in Listing 7-13.</p>
<figure class="listing" id="listing-7-13">
<span class="file-name">Filename: src/lib.rs</span>
<pre><code class="language-rust noplayground test_harness">mod front_of_house {
pub mod hosting {
pub fn add_to_waitlist() {}
}
}
use crate::front_of_house::hosting::add_to_waitlist;
pub fn eat_at_restaurant() {
add_to_waitlist();
}</code></pre>
<figcaption><a href="#listing-7-13">Listing 7-13</a>: Bringing the <code>add_to_waitlist</code> function into scope with <code>use</code>, which is unidiomatic</figcaption>
</figure>
<p>Although both Listing 7-11 and Listing 7-13 accomplish the same task, Listing
7-11 is the idiomatic way to bring a function into scope with <code>use</code>. Bringing
the functions parent module into scope with <code>use</code> 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 isnt locally defined
while still minimizing repetition of the full path. The code in Listing 7-13 is
unclear as to where <code>add_to_waitlist</code> is defined.</p>
<p>On the other hand, when bringing in structs, enums, and other items with <code>use</code>,
its idiomatic to specify the full path. Listing 7-14 shows the idiomatic way
to bring the standard librarys <code>HashMap</code> struct into the scope of a binary
crate.</p>
<figure class="listing" id="listing-7-14">
<span class="file-name">Filename: src/main.rs</span>
<pre class="playground"><code class="language-rust edition2024">use std::collections::HashMap;
fn main() {
let mut map = HashMap::new();
map.insert(1, 2);
}</code></pre>
<figcaption><a href="#listing-7-14">Listing 7-14</a>: Bringing <code>HashMap</code> into scope in an idiomatic way</figcaption>
</figure>
<p>Theres no strong reason behind this idiom: Its just the convention that has
emerged, and folks have gotten used to reading and writing Rust code this way.</p>
<p>The exception to this idiom is if were bringing two items with the same name
into scope with <code>use</code> statements, because Rust doesnt allow that. Listing 7-15
shows how to bring two <code>Result</code> types into scope that have the same name but
different parent modules, and how to refer to them.</p>
<figure class="listing" id="listing-7-15">
<span class="file-name">Filename: src/lib.rs</span>
<pre><code class="language-rust noplayground">use std::fmt;
use std::io;
fn function1() -&gt; fmt::Result {
// --snip--
<span class="boring"> Ok(())
</span>}
fn function2() -&gt; io::Result&lt;()&gt; {
// --snip--
<span class="boring"> Ok(())
</span>}</code></pre>
<figcaption><a href="#listing-7-15">Listing 7-15</a>: Bringing two types with the same name into the same scope requires using their parent modules.</figcaption>
</figure>
<p>As you can see, using the parent modules distinguishes the two <code>Result</code> types.
If instead we specified <code>use std::fmt::Result</code> and <code>use std::io::Result</code>, wed
have two <code>Result</code> types in the same scope, and Rust wouldnt know which one we
meant when we used <code>Result</code>.</p>
<h3 id="providing-new-names-with-the-as-keyword"><a class="header" href="#providing-new-names-with-the-as-keyword">Providing New Names with the <code>as</code> Keyword</a></h3>
<p>Theres another solution to the problem of bringing two types of the same name
into the same scope with <code>use</code>: After the path, we can specify <code>as</code> and a new
local name, or <em>alias</em>, for the type. Listing 7-16 shows another way to write
the code in Listing 7-15 by renaming one of the two <code>Result</code> types using <code>as</code>.</p>
<figure class="listing" id="listing-7-16">
<span class="file-name">Filename: src/lib.rs</span>
<pre><code class="language-rust noplayground">use std::fmt::Result;
use std::io::Result as IoResult;
fn function1() -&gt; Result {
// --snip--
<span class="boring"> Ok(())
</span>}
fn function2() -&gt; IoResult&lt;()&gt; {
// --snip--
<span class="boring"> Ok(())
</span>}</code></pre>
<figcaption><a href="#listing-7-16">Listing 7-16</a>: Renaming a type when its brought into scope with the <code>as</code> keyword</figcaption>
</figure>
<p>In the second <code>use</code> statement, we chose the new name <code>IoResult</code> for the
<code>std::io::Result</code> type, which wont conflict with the <code>Result</code> from <code>std::fmt</code>
that weve also brought into scope. Listing 7-15 and Listing 7-16 are
considered idiomatic, so the choice is up to you!</p>
<h3 id="re-exporting-names-with-pub-use"><a class="header" href="#re-exporting-names-with-pub-use">Re-exporting Names with <code>pub use</code></a></h3>
<p>When we bring a name into scope with the <code>use</code> keyword, the name is private to
the scope into which we imported it. To enable code outside that scope to refer
to that name as if it had been defined in that scope, we can combine <code>pub</code> and
<code>use</code>. This technique is called <em>re-exporting</em> because were bringing an item
into scope but also making that item available for others to bring into their
scope.</p>
<p>Listing 7-17 shows the code in Listing 7-11 with <code>use</code> in the root module
changed to <code>pub use</code>.</p>
<figure class="listing" id="listing-7-17">
<span class="file-name">Filename: src/lib.rs</span>
<pre><code class="language-rust noplayground test_harness">mod front_of_house {
pub mod hosting {
pub fn add_to_waitlist() {}
}
}
pub use crate::front_of_house::hosting;
pub fn eat_at_restaurant() {
hosting::add_to_waitlist();
}</code></pre>
<figcaption><a href="#listing-7-17">Listing 7-17</a>: Making a name available for any code to use from a new scope with <code>pub use</code></figcaption>
</figure>
<p>Before this change, external code would have to call the <code>add_to_waitlist</code>
function by using the path
<code>restaurant::front_of_house::hosting::add_to_waitlist()</code>, which also would have
required the <code>front_of_house</code> module to be marked as <code>pub</code>. Now that this <code>pub use</code> has re-exported the <code>hosting</code> module from the root module, external code
can use the path <code>restaurant::hosting::add_to_waitlist()</code> instead.</p>
<p>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 wont think about the parts of the restaurant in those terms. With <code>pub use</code>, 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. Well look at another example of <code>pub use</code>
and how it affects your crates documentation in <a href="../ch14/ch14-02-publishing-to-crates-io.html#exporting-a-convenient-public-api">“Exporting a Convenient Public
API”</a><!-- ignore --> in Chapter 14.</p>
<h3 id="using-external-packages"><a class="header" href="#using-external-packages">Using External Packages</a></h3>
<p>In Chapter 2, we programmed a guessing game project that used an external
package called <code>rand</code> to get random numbers. To use <code>rand</code> in our project, we
added this line to <em>Cargo.toml</em>:</p>
<!-- 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
-->
<figure class="listing">
<span class="file-name">Filename: Cargo.toml</span>
<pre><code class="language-toml">rand = "0.8.5"
</code></pre>
</figure>
<p>Adding <code>rand</code> as a dependency in <em>Cargo.toml</em> tells Cargo to download the
<code>rand</code> package and any dependencies from <a href="https://crates.io/">crates.io</a> and
make <code>rand</code> available to our project.</p>
<p>Then, to bring <code>rand</code> definitions into the scope of our package, we added a
<code>use</code> line starting with the name of the crate, <code>rand</code>, and listed the items we
wanted to bring into scope. Recall that in <a href="../ch02/ch02-00-guessing-game-tutorial.html#generating-a-random-number">“Generating a Random
Number”</a><!-- ignore --> in Chapter 2, we brought the <code>Rng</code> trait into
scope and called the <code>rand::thread_rng</code> function:</p>
<pre><code class="language-rust ignore"><span class="boring">use std::io;
</span><span class="boring">
</span>use rand::Rng;
fn main() {
<span class="boring"> println!("Guess the number!");
</span><span class="boring">
</span> let secret_number = rand::thread_rng().gen_range(1..=100);
<span class="boring">
</span><span class="boring"> println!("The secret number is: {secret_number}");
</span><span class="boring">
</span><span class="boring"> println!("Please input your guess.");
</span><span class="boring">
</span><span class="boring"> let mut guess = String::new();
</span><span class="boring">
</span><span class="boring"> io::stdin()
</span><span class="boring"> .read_line(&amp;mut guess)
</span><span class="boring"> .expect("Failed to read line");
</span><span class="boring">
</span><span class="boring"> println!("You guessed: {guess}");
</span>}</code></pre>
<p>Members of the Rust community have made many packages available at
<a href="https://crates.io/">crates.io</a>, and pulling any of them into your package
involves these same steps: listing them in your packages <em>Cargo.toml</em> file and
using <code>use</code> to bring items from their crates into scope.</p>
<p>Note that the standard <code>std</code> library is also a crate thats external to our
package. Because the standard library is shipped with the Rust language, we
dont need to change <em>Cargo.toml</em> to include <code>std</code>. But we do need to refer to
it with <code>use</code> to bring items from there into our packages scope. For example,
with <code>HashMap</code> we would use this line:</p>
<pre class="playground"><code class="language-rust edition2024"><span class="boring">#![allow(unused)]
</span><span class="boring">fn main() {
</span>use std::collections::HashMap;
<span class="boring">}</span></code></pre>
<p>This is an absolute path starting with <code>std</code>, the name of the standard library
crate.</p>
<!-- Old headings. Do not remove or links may break. -->
<p><a id="using-nested-paths-to-clean-up-large-use-lists"></a></p>
<h3 id="using-nested-paths-to-clean-up-use-lists"><a class="header" href="#using-nested-paths-to-clean-up-use-lists">Using Nested Paths to Clean Up <code>use</code> Lists</a></h3>
<p>If were 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 <code>use</code> statements we had in the guessing game in Listing 2-4
bring items from <code>std</code> into scope:</p>
<figure class="listing">
<span class="file-name">Filename: src/main.rs</span>
<pre><code class="language-rust ignore"><span class="boring">use rand::Rng;
</span>// --snip--
use std::cmp::Ordering;
use std::io;
// --snip--
<span class="boring">
</span><span class="boring">fn main() {
</span><span class="boring"> println!("Guess the number!");
</span><span class="boring">
</span><span class="boring"> let secret_number = rand::thread_rng().gen_range(1..=100);
</span><span class="boring">
</span><span class="boring"> println!("The secret number is: {secret_number}");
</span><span class="boring">
</span><span class="boring"> println!("Please input your guess.");
</span><span class="boring">
</span><span class="boring"> let mut guess = String::new();
</span><span class="boring">
</span><span class="boring"> io::stdin()
</span><span class="boring"> .read_line(&amp;mut guess)
</span><span class="boring"> .expect("Failed to read line");
</span><span class="boring">
</span><span class="boring"> println!("You guessed: {guess}");
</span><span class="boring">
</span><span class="boring"> match guess.cmp(&amp;secret_number) {
</span><span class="boring"> Ordering::Less =&gt; println!("Too small!"),
</span><span class="boring"> Ordering::Greater =&gt; println!("Too big!"),
</span><span class="boring"> Ordering::Equal =&gt; println!("You win!"),
</span><span class="boring"> }
</span><span class="boring">}</span></code></pre>
</figure>
<p>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.</p>
<figure class="listing" id="listing-7-18">
<span class="file-name">Filename: src/main.rs</span>
<pre><code class="language-rust ignore"><span class="boring">use rand::Rng;
</span>// --snip--
use std::{cmp::Ordering, io};
// --snip--
<span class="boring">
</span><span class="boring">fn main() {
</span><span class="boring"> println!("Guess the number!");
</span><span class="boring">
</span><span class="boring"> let secret_number = rand::thread_rng().gen_range(1..=100);
</span><span class="boring">
</span><span class="boring"> println!("The secret number is: {secret_number}");
</span><span class="boring">
</span><span class="boring"> println!("Please input your guess.");
</span><span class="boring">
</span><span class="boring"> let mut guess = String::new();
</span><span class="boring">
</span><span class="boring"> io::stdin()
</span><span class="boring"> .read_line(&amp;mut guess)
</span><span class="boring"> .expect("Failed to read line");
</span><span class="boring">
</span><span class="boring"> let guess: u32 = guess.trim().parse().expect("Please type a number!");
</span><span class="boring">
</span><span class="boring"> println!("You guessed: {guess}");
</span><span class="boring">
</span><span class="boring"> match guess.cmp(&amp;secret_number) {
</span><span class="boring"> Ordering::Less =&gt; println!("Too small!"),
</span><span class="boring"> Ordering::Greater =&gt; println!("Too big!"),
</span><span class="boring"> Ordering::Equal =&gt; println!("You win!"),
</span><span class="boring"> }
</span><span class="boring">}</span></code></pre>
<figcaption><a href="#listing-7-18">Listing 7-18</a>: Specifying a nested path to bring multiple items with the same prefix into scope</figcaption>
</figure>
<p>In bigger programs, bringing many items into scope from the same crate or
module using nested paths can reduce the number of separate <code>use</code> statements
needed by a lot!</p>
<p>We can use a nested path at any level in a path, which is useful when combining
two <code>use</code> statements that share a subpath. For example, Listing 7-19 shows two
<code>use</code> statements: one that brings <code>std::io</code> into scope and one that brings
<code>std::io::Write</code> into scope.</p>
<figure class="listing" id="listing-7-19">
<span class="file-name">Filename: src/lib.rs</span>
<pre><code class="language-rust noplayground">use std::io;
use std::io::Write;</code></pre>
<figcaption><a href="#listing-7-19">Listing 7-19</a>: Two <code>use</code> statements where one is a subpath of the other</figcaption>
</figure>
<p>The common part of these two paths is <code>std::io</code>, and thats the complete first
path. To merge these two paths into one <code>use</code> statement, we can use <code>self</code> in
the nested path, as shown in Listing 7-20.</p>
<figure class="listing" id="listing-7-20">
<span class="file-name">Filename: src/lib.rs</span>
<pre><code class="language-rust noplayground">use std::io::{self, Write};</code></pre>
<figcaption><a href="#listing-7-20">Listing 7-20</a>: Combining the paths in Listing 7-19 into one <code>use</code> statement</figcaption>
</figure>
<p>This line brings <code>std::io</code> and <code>std::io::Write</code> into scope.</p>
<!-- Old headings. Do not remove or links may break. -->
<p><a id="the-glob-operator"></a></p>
<h3 id="importing-items-with-the-glob-operator"><a class="header" href="#importing-items-with-the-glob-operator">Importing Items with the Glob Operator</a></h3>
<p>If we want to bring <em>all</em> public items defined in a path into scope, we can
specify that path followed by the <code>*</code> glob operator:</p>
<pre class="playground"><code class="language-rust edition2024"><span class="boring">#![allow(unused)]
</span><span class="boring">fn main() {
</span>use std::collections::*;
<span class="boring">}</span></code></pre>
<p>This <code>use</code> statement brings all public items defined in <code>std::collections</code> 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. Additionally, if the dependency changes its definitions, what
youve imported changes as well, which may lead to compiler errors when you
upgrade the dependency if the dependency adds a definition with the same name
as a definition of yours in the same scope, for example.</p>
<p>The glob operator is often used when testing to bring everything under test into
the <code>tests</code> module; well talk about that in <a href="../ch11/ch11-01-writing-tests.html#how-to-write-tests">“How to Write
Tests”</a><!-- ignore --> in Chapter 11. The glob operator is also
sometimes used as part of the prelude pattern: See <a href="../std/prelude/index.html#other-preludes">the standard library
documentation</a><!-- ignore --> for more
information on that pattern.</p>
</body>
</html>