We can't find the internet
Attempting to reconnect
Something went wrong!
Attempting to reconnect
← Modules, Visibility, Testing and Docs step 5 of 22
use declarations: nested groups, as, self, and _
A use declaration does one thing: it creates a name binding in the current
module. Not an import in the Python sense, not a link step — a local alias for a
path. Once you see it that way, nested groups and as _ stop being syntax to
memorise.
pub fn expand_use(decl: &str) -> Vec<(String, String)>
Parse one use declaration and return every (full_path, bound_name) pair it
creates, sorted. Malformed input, and globs, produce an empty vec.
use std::collections::HashMap;
-> [("std::collections::HashMap", "HashMap")]
use std::collections::{BTreeSet, hash_map::{self, HashMap}};
-> [("std::collections::BTreeSet", "BTreeSet"),
("std::collections::hash_map", "hash_map"),
("std::collections::hash_map::HashMap", "HashMap")]
use std::io::Write as _;
-> [("std::io::Write", "_")]
The grammar, in four bullets
-
A leaf is a path, optionally followed by
as name. The bound name is the alias if there is one, otherwise the last segment. -
A group is
prefix::{ … }. Everything inside inherits the prefix, and groups nest arbitrarily deep.use std::{fmt, io};is two bindings from one line. -
selfinside a group binds the module the group hangs off:hash_map::{self, HashMap}binds bothhash_map(the module) andHashMap(the type). That one line creates three bindings in the example above, which is why people find it confusing. -
as _binds the name_, which is to say: it binds nothing you can spell.
Why as _ exists, and why it is almost never taught
To call a trait’s methods, the trait has to be in scope:
use std::io::Write; // without this, `.write_all()` does not exist
file.write_all(b"hi")?;
This is a genuine cliff for beginners — “the method is right there in the docs,
why is it not on my value” — and the answer is always “you did not import the
trait”. But now the name Write is taken, and you may well have your own
Write, or a second trait from another crate with the same name. as _ brings
the methods without the name:
use std::io::Write as _;
The trait is used, so unused_imports stays quiet either way. clippy:: unused_trait_names is the lint that notices the name itself is never mentioned
and suggests as _. Two tools, two opinions, both correct — rustc is asking
“is this import doing anything?” and clippy is asking “is it doing only the
thing you meant?”.
While we are here: use std::string::String; is entirely redundant, because
String is already in the prelude. unused_imports will not catch it (the name
is used); the allow-by-default redundant_imports will.
Contract
-
A well-formed declaration starts with
usefollowed by whitespace and ends with;. Anything else returns an empty vec. -
Braces must balance, and a group must be the last thing in its subtree —
use a::{b}::c;is not a thing. -
Path segments are identifiers. A
*anywhere means this is a glob, which is out of scope for this parser (globs get their own item, 10.6) — return an empty vec. - A trailing comma inside a group is legal and binds nothing extra.
- Sort by full path, then by bound name.
Stuck?
Rust reference solution
Sign in to attempt this problem and reveal the reference solution.