The use declaration The use declaration can be used to bind a full path to a new name, for easier access. It is often used like this: use crate::deeply::nested::{ my_first_function, my_second_function, AndATraitType }; fn main() { my_first_...
super and self The super and self keywords can be used in the path to remove ambiguity when accessing items and to prevent unnecessary hardcoding of paths. fn function() { println!("called `function()`"); } mod cool { pub fn function() { pr...
File hierarchy Modules can be mapped to a file/directory hierarchy. Let's break down the visibility example in files: $ tree . . ├── my │ ├── inaccessible.rs │ └── nested.rs ├── my.rs └── split.rs In split.rs: // This declaration will look...
Crates A crate is a compilation unit in Rust. Whenever rustc some_file.rs is called, some_file.rs is treated as the crate file. If some_file.rs has mod declarations in it, then the contents of the module files would be inserted in places wh...
Creating a Library Let's create a library, and then see how to link it to another crate. In rary.rs: pub fn public_function() { println!("called rary's `public_function()`"); } fn private_function() { println!("called rary's `private_functi...
Using a Library To link a crate to this new library you may use rustc's --extern flag. All of its items will then be imported under a module named the same as the library. This module generally behaves the same way as any other module. // e...
Cargo cargo is the official Rust package management tool. It has lots of really useful features to improve code quality and developer velocity! These include • Dependency management and integration with crates.io (the official Rust package...
Dependencies Most programs have dependencies on some libraries. If you have ever managed dependencies by hand, you know how much of a pain this can be. Luckily, the Rust ecosystem comes standard with cargo! cargo can manage dependencies for...
Conventions In the previous chapter, we saw the following directory hierarchy: foo ├── Cargo.toml └── src └── main.rs Suppose that we wanted to have two binaries in the same project, though. What then? It turns out that cargo supports this....
Testing As we know testing is integral to any piece of software! Rust has first-class support for unit and integration testing (see this chapter in TRPL). From the testing chapters linked above, we see how to write unit tests and integratio...
Build Scripts Sometimes a normal build from cargo is not enough. Perhaps your crate needs some pre-requisites before cargo will successfully compile, things like code generation, or some native code that needs to be compiled. To solve this...
Attributes An attribute is metadata applied to some module, crate or item. This metadata can be used to/for: • conditional compilation of code • set crate name, version and type (binary or library) • disable lints (warnings) • enable compil...
dead_code The compiler provides a dead_code lint that will warn about unused functions. An attribute can be used to disable the lint. fn used_function() {} // `#[allow(dead_code)]` is an attribute that disables the `dead_code` lint #[allow(...
Crates The crate_type attribute can be used to tell the compiler whether a crate is a binary or a library (and even which type of library), and the crate_name attribute can be used to set the name of the crate. However, it is important to n...
cfg Configuration conditional checks are possible through two different operators: • the cfg attribute: #[cfg(...)] in attribute position • the cfg! macro: cfg!(...) in boolean expressions While the former enables conditional compilation, t...
Custom Some conditionals like target_os are implicitly provided by rustc, but custom conditionals must be passed to rustc using the --cfg flag. #[cfg(some_condition)] fn conditional_function() { println!("condition met!"); } fn main() { con...
Generics Generics is the topic of generalizing types and functionalities to broader cases. This is extremely useful for reducing code duplication in many ways, but can call for rather involved syntax. Namely, being generic requires taking g...
Functions The same set of rules can be applied to functions: a type T becomes generic when preceded by <T>. Using generic functions sometimes requires explicitly specifying type parameters. This may be the case if the function is called whe...
Implementation Similar to functions, implementations require care to remain generic. struct S; // Concrete type `S` struct GenericVal<T>(T); // Generic type `GenericVal` // impl of GenericVal where we explicitly specify type parameters: imp...
Traits Of course traits can also be generic. Here we define one which reimplements the Drop trait as a generic method to drop itself and an input. // Non-copyable types. struct Empty; struct Null; // A trait generic over `T`. trait DoubleDr...