We can't find the internet
Attempting to reconnect
Something went wrong!
Attempting to reconnect
← Modules, Visibility, Testing and Docs step 7 of 22
Three namespaces: types, values, and macros
A namespace is a separate table of names. Two declarations conflict only when they put the same name into the same table, in the same scope. Rust keeps several such tables. Three of them hold the names of items (the things you declare at module level), and they explain a group of rules that otherwise look arbitrary.
| namespace | what it holds (the parts used in this exercise in bold) |
|---|---|
| type | modules, structs, enums, unions, traits, type aliases; also built-in types such as i32 and generic type parameters |
| value | functions, constants, statics, and the constructors of unit and tuple structs; also local variables and enum variant constructors |
| macro | macro_rules! macros; also procedural macros (function-like, attribute and derive) and built-in attributes |
Rust also has a lifetime namespace ('a) and a label namespace ('outer: on a
loop). Neither can hold an item name, so this exercise leaves them out.
Some consequences:
- A module and a function may share a name.
mod foo {}andfn foo() {}in the same module compile, because one name is in the type namespace and the other is in the value namespace. - A module and a macro may share a name. The standard library has both a
std::vecmodule and avec!macro. - The
!inprintln!("hi")marks a macro call, and the name is then looked up in the macro namespace. A function you write calledprintlndoes not conflict with it;println!(...)andprintln()call different things.
Which structs occupy two namespaces
A struct always puts its name in the type namespace. Whether it also puts the name in the value namespace depends on its shape:
- Braced struct,
struct Foo { x: i32 }orstruct Foo {}: type only. You build one withFoo { x: 1 }, which is special syntax, not a value calledFoo. - Unit struct,
struct Foo;: type and value. The bare expressionFoois the one value of that type, so the nameFoomust exist as a value. - Tuple struct,
struct Foo(i32);: type and value. The valueFoois a constructor function that takes ani32and returns aFoo. That is whyFoo(3)looks like a function call, and why you can write.map(Foo).
So these two pairs behave differently:
struct Foo {} fn Foo() {} // compiles (with a naming-style warning)
struct Foo; fn Foo() {} // error[E0428]: the name `Foo` is defined multiple times
A realistic version of the second line:
struct Config; // puts `Config` in the type and value namespaces
fn Config() -> Config { Config } // E0428: `Config` is already a value
The headline only says the name is "defined multiple times". The note under it
says which table was involved: "Config must be defined only once in the value
namespace of this module". The unit struct had already claimed the value name.
Related compiler errors
The compiler uses different error codes depending on where the conflicting
names came from. All three below report "the name X is defined multiple
times":
- E0428: two items declared in the same module put the same name in the same namespace. Rename one of them.
- E0255: a
useimport brings in a name that an item in the same module already declares in the same namespace, as inuse std::fmt::Result; struct Result;. Rename the import withas, or rename the item. - E0252: two
useimports bring in the same name in the same namespace, as inuse std::fmt::Result; use std::io::Result;. Rename one withas.
Glob imports (use a::*;) are treated differently. If two globs both provide a
name, there is no error until code actually uses that name; then the compiler
reports E0659, "S is ambiguous".
The task
pub fn collisions(decls: Vec<String>) -> Vec<String>
Each string is a simplified declaration. Treat all of them as items declared in one module. Return every name that is declared two or more times in the same namespace, sorted, with no duplicates.
| form | namespaces it occupies |
|---|---|
struct Name {} |
type |
struct Name; |
type and value |
struct Name() |
type and value |
enum Name, trait Name, type Name, union Name, mod Name |
type |
fn Name, const Name, static Name |
value |
macro_rules! Name |
macro |
These forms are shorthand, not complete Rust. struct Name() stands for a tuple
struct (real code would be struct Name(i32); or similar), and fn Name stands
for a whole function.
The macro_rules! simplification. In real code, a plain macro_rules!
definition is scoped by its position in the source, and a second definition with
the same name shadows the first instead of causing an error. The exercise
instead counts two macro_rules! Name lines as a collision. That matches what
happens when both are marked #[macro_export], which gives each one a path at
the crate root: the compiler then reports E0428 for them.
Contract
- A recognised declaration is a keyword followed by a name, separated by
whitespace.
macro_rules!includes its!. A struct's name is followed by exactly one of the suffixes{},;or(); spaces before or inside the suffix do not matter, sostruct Foo {},struct Foo{}andstruct Foo { }are the same declaration. Struct names consist of ASCII letters, digits and underscores, and all names in the tests do. No test puts whitespace inside a name. - Any string that does not match one of the forms is ignored. Examples: an empty
string,
struct Namewith no suffix,fnwith no name, or a non-struct keyword followed by more than one word. - Names are compared exactly, so
logandLogare different names. - A name collides when its count in any one namespace reaches two. A unit or
tuple struct adds one to both its type count and its value count, so
struct Foo;plusfn Foocollides in the value namespace only. - Return each colliding name once, even if it collides in more than one namespace or appears three or more times.
- Sort by byte order (the ordering of Rust's
String), so uppercase ASCII letters come before lowercase:["Zeta", "log"]. - An empty input, or one with no collisions, returns an empty list.
Your code, saved here
Sign in to access your accepted solutions and saved draft history. You can keep reading the lesson without an account.
Sign in to your accountStuck?
Rust reference solution
Sign in to track your attempts toward unlocking the reference solution.