Skip to content

Latest commit

 

History

History
151 lines (112 loc) · 3.39 KB

imports-and-modules.md

File metadata and controls

151 lines (112 loc) · 3.39 KB

Imports and Modules

Namespaces

  • A namespace is simply a way to distinguish two things that have the same name.
  • It provides a scope to the identifiers within it.

Rust supports namespacing in two ways:

  1. Crates for re-usable software libraries
  2. Modules for breaking up your crates

Crates

  • A crate is the unit of Rust software suitable for shipping.
  • Yes, it's a deliberate pun.
  • The Rust Standard Library is a crate.
  • Binary Crates and Library Crates

There's no build file

  • Have you noticed that Cargo.toml says nothing about which files to compile?
  • Cargo starts with lib.rs for a library or the relevant main.rs for a binary
  • It then finds all the modules

Modules

  • A module is block of source code within a crate
  • It qualifies the names of everything in it
  • It has a parent module (or it is the crate root)
  • It can have child modules
  • The crate is therefore a tree

Standard Library

We've been using modules from the Rust Standard Library...

use std::fs;
use std::io::prelude::*;

fn main() -> std::io::Result<()> {
    let mut f = fs::File::create("hello.txt")?;
    f.write(b"hello")?;
    Ok(())
}

Note:

Prelude modules, like std::io::prelude, usually contain important traits and you usually want to import all of it with a * wildcard.

In-line modules

You can declare a module in-line:

mod animals {
    pub struct Cat { name: String }

    impl Cat {
        pub fn new(name: &str) -> Cat {
            Cat { name: name.to_owned() }
        }
    }
}

fn main() {
    let c = animals::Cat::new("Mittens");
    // let c = animals::Cat { name: "Mittens".to_string() };
}

Modules in a file

You can also put modules in their own file on disk.

This will load from either ./animals/mod.rs or ./animals.rs:

mod animals;

fn main() {
    let c = animals::Cat::new("Mittens");
    // let c = animals::Cat { name: "Mittens".to_string() };
}

Modules can be nested...

~/probe-run $ tree src
src
├── backtrace
│   ├── mod.rs
│   ├── pp.rs
│   ├── symbolicate.rs
│   └── unwind.rs
├── canary.rs
├── cli.rs
├── cortexm.rs
├── dep
│   ├── cratesio.rs
│   ├── mod.rs
│   ├── rust_repo.rs
│   ├── rust_std
│   │   └── toolchain.rs
│   ├── rust_std.rs
│   └── rustc.rs
├── elf.rs
├── main.rs
├── probe.rs
├── registers.rs
├── stacked.rs
└── target_info.rs

Note:

The choice about foo.rs vs foo/mod.rs often depends on whether mod foo itself has any child modules.

The example is from the Knurling tool probe-run.

What kind of import?

Choosing whether to import the parent module, or each of the types contained within, is something of an art form.

use std::fs;
use std::collections::VecDeque;
use std::io::prelude::*;

Standard Library

There's also a more compact syntax for imports.

use std::{fs, io::prelude::*};

fn main() -> std::io::Result<()> {
    let mut f = fs::File::create("hello.txt")?;
    f.write(b"hello")?;
    Ok(())
}