Skip to content

Instantly share code, notes, and snippets.

@lifthrasiir
Created March 11, 2014 06:29
Show Gist options
  • Save lifthrasiir/9480585 to your computer and use it in GitHub Desktop.
Save lifthrasiir/9480585 to your computer and use it in GitHub Desktop.
Pub, use and mod

There are some intertwined concepts in Rust module system:

  • Visibility
  • Physical file path
  • Logical module path

One should note that these three concepts are completely independent to others. While rustc automatically infers the physical file path from the logical module path, it is just for the convenience and you can always override this behavior with #[path] attribute.

I'll give some practical examples to illustrate the differences among these three concepts.

One file, one module

// a.rs
fn answer() -> uint { 42 }
fn main() {
    println!("{}", answer());
}

This is the simplest module structure possible in Rust. There is exactly one module (unnamed), which is also a root module for the current crate. The root module can have crate attributes for the current crate; it can be, for example, used to explicitly set the crate name to something other than a (automatically inferred from the file name).

The module can have multiple items (functions, statics, uses and other modules). Items have visibilities (public or private) attached to them. The visibilities are ignored when accessing items from the same module, though, so you won't need any visibility specifications in this file.

One file, two modules, no use

// a.rs
mod universe {
    pub fn answer() -> uint { 42 }
}

fn main() {
    println!("{}", universe::answer());
}

This time there are two modules, an unnamed root module and a module named universe. The universe module is defined in the root module, so the root module does not need visibility for referring universe. But universe::answer function is not defined in the root module, so it needs pub for referring universe::answer.

The position of module items is not quite important. It can be important for macros (which only obeys the basic nesting and source code order), so you need to be a bit more careful when you are using macros within modules.

One file, two modules, one use

// a.rs
use universe::answer;

mod universe {
    pub fn answer() -> uint { 42 }
}

fn main() {
    println!("{}", answer());
}

This is same as above but uses an use item to import the visible item into the root module. When you have use a::b::c;, you need accesses to a, a::b and a::b::c. In this case, the root module defined universe so it can see that, and universe::answer is visible from outside.

The order of use and mod is again not important. It seemingly violates the use-after-definition principle, but it's how Rust currently does that.

Two files, two modules, one use (1)

// life_universe_and_everything.rs
pub fn answer() -> uint { 42 }

// a.rs
use universe::answer;

#[path="life_universe_and_everything.rs"] mod universe;

fn main() {
    println!("{}", answer());
}

This is same as above, but universe no longer has its contents (note the semicolon after mod universe). Instead, its contents is in the separate file pointed by #[path] attribute. Everything else didn't change; the file is just a convenient way to organize a large crate with many modules inside. In fact, even for the macros, mod foo; will just act like mod foo { <contents of foo.rs inside> }.

Two files, two modules, one use (2)

// universe.rs
pub fn answer() -> uint { 42 }

// a.rs
use universe::answer;

mod universe;

fn main() {
    println!("{}", answer());
}

This is pretty much same as above but there is no #[path] attribute. Rustc will assume that the physical file name for that module is same as the module name plus .rs extension. Sometimes, you need to organize modules a bit further...

Two files, two modules, one use (3)

// universe/mod.rs
pub fn answer() -> uint { 42 }

// a.rs
use universe::answer;

mod universe;

fn main() {
    println!("{}", answer());
}

...like this. Rustc will try module_name.rs first, and if it does not exist, will try module_name/mod.rs instead. (Rustc will helpfully report an error when both exist.)


TODO

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment