Notes (TRPL 07/21): Packages, Crates, and Modules

7 Packages, Crates, Modules

7.1 Packages and Crates for Making Libraries and Executables

cargo looks for src/main.rs to build a binary by convention, if no other source files are specified with e.g.:

[[bin]]
name = "main2"
path = "src/main2.rs"

7.2 The Module System to Control Scope and Privacy

Interesting, modules in rust do not have to correspond one-to-one with source files. A file can contain multiple modules.

Modules as the Privacy Boundary

Access upwards is implicitly allowed, access downwards has to be explicitly granted.

Privacy rules apply to any named expression, i.e. functions and structs as well as modules.

This feels very object-oriented.

The use Keword to Bring Paths into a scope

The a::b::c::d() pattern is verbose, we can bring d into scope with

use crate::a::b::c::d

But if d is function then it might be preferable to import the containing module c:

use crate::a::b::c

And call d with c::d()

Idiomatic use Paths for Functions vs. Other Items

It’s idiomatic to import functions with

use crate::module

module::function();

But to import structs or enums with

use crate::module::StructEnum

StructEnum::function();

Unless this would create a namespace conflict, in which you can disambiguate by importing the containing modules, or by using the as keyword.

Renaming Types Brought Into Scope with the as Keyword

With as you can assign a module to a name in your namespace:

use crate::module::StructEnum as SE

SE::function();

Nested Paths for Cleaning Up Large use Lists

Some nice tools here for nicely managing import lists:

use std::io;
use std::io::Write;
use std::cmp::Ordering;

becomes

use  std::{
  cmp::Ordering,
  io::{self, Write}
};

which even gets nicely autoformatted by rustfmt!

And then of course the notorious glob operator:

use std::collections::*;

It’s a good rule of thumb to always be very very wary of the glob. Much wailing and gnashing of teeth has resulted from careless globbing, particularly when used as a command line argument (cf. rm -rf). In this case, though you probably won’t do anything other than make your scope messy. Nevertheless, ¡Cuidado!

Separating Modules into Different Files

If we have a file src/separate_file.rs:

pub fn do_something() {
  println!("doing something");
}

pub mod separate_file_module {
  pub fn do_another_thing() {
    println!("doing another thing");
  }
}

Then from src/main.rs we can do:

mod separate_file;

fn main() {

  separate_file::do_something();
  separate_file::separate_file_module::do_another_thing();
}

Which calls the functions as expected.