We can't find the internet
Attempting to reconnect
Something went wrong!
Attempting to reconnect
← Modules, Visibility, Testing and Docs step 6 of 22
Glob imports, shadowing, and ambiguity
use foo::*; drags every public name out of foo into your module. It is the
fastest way to make a Rust codebase unreadable, and it is also, occasionally,
exactly right. What makes it worth a whole item is that the shadowing rules are
not obvious, and experienced people guess.
pub fn resolve(bindings: Vec<(String, String, String)>, name: &str) -> String
Each binding is (kind, name, target_path) with kind one of "item",
"use", "glob", "prelude". Return the path name resolves to, or
"ambiguous", or "unresolved".
The precedence ladder
item ≻ explicit use ≻ glob ≻ prelude
An item you declared beats a name you imported. An explicit use beats a glob.
A glob beats the prelude — which is why use my_prelude::*; can shadow Result
and nobody notices for a while.
Two things follow that are easy to get wrong:
-
The first tier with anything to say wins outright. If an explicit
usebinds the name, two conflicting globs below it are simply never consulted, and there is no error. Ambiguity is decided within a tier. - Two globs that pull in the same path are not a conflict. There is still only one thing the name could mean. Deduplicate by target before you count.
Two globs pulling in different items with the same name is
E0659 — X is ambiguous, and the timing of that error is the interesting
part: it does not fire when you write the globs. It fires the first time
somebody uses the name. So the error appears in a file nobody edited, blaming
a line that has been there for months, because a dependency you upgraded added
one public item.
pub use x::*; twice is worse
Re-exporting two globs with an overlapping name produces the warn-by-default
ambiguous_glob_reexports and silently drops one of them from your public
API. Not an error, not a resolution failure — one of the two names is simply
not there for your users. This is the strongest single argument against glob
re-exports in a library.
The community genuinely disagrees
clippy::wildcard_imports (pedantic, off by default) wants globs gone. Its
carve-outs tell you where the argument sits: it deliberately exempts paths
containing prelude, and use super::*; inside a module whose name
contains “test”. Those two are considered idiomatic by nearly everyone.
clippy::enum_glob_use is narrower and targets use Ordering::*;, which reads
beautifully inside a match and destroys your ability to grep for Less.
There is no settled answer. What is settled is that you should be able to predict what a glob does before you write one, which is what this problem is for.
Contract
-
Unknown name with no bindings at all:
"unresolved". -
More than one distinct target in the winning tier:
"ambiguous". - Duplicate identical bindings in a tier collapse to one.
Stuck?
Rust reference solution
Sign in to attempt this problem and reveal the reference solution.