Organization
Rust has a number of features that allow to manage code’s organization, including which details are exposed, which details are private, and what names are in each scope in programs. These features, sometimes collectively referred to as the module system, include:
- Workspaces: acts like a solution in .NET. It may contain multiple packages.
- Packages: one or more crates that provide a set of functionality. A
package contains a
Cargo.toml
file. It’s like a project in .NET. - Crates: a binary or library. It’s a compilation unit for the compiler. Other languages treat a single file as a compilation unit
- Modules: let us organize code within a crate into groups for readability and easy reuse.
- Paths: A way of naming an item, such as a struct, function, or module.
Packages
A package contains crates. It can be as many binary crates as needed and just
one library crate.
We create packages with cargo new my-project-name
.
Workspaces
A workspace may contain multiple packages. We need to define how packages are related (which one depends on which one).
We can specify project to run in a workspace with cargo run -p my-package
.
Pckages in a workspace use the same versions of dependencies. There’s just one
Cargo.lock
file.
Modules
Modules control encapsulation. Some items might be public, others can be private. Modules may be nested.
Example:
Modules may contain definitions of anything (modules, functions, structs, enums, etc.).
The root of every module is crate
. It is either src/main.rs
or src/lib.rs
.
There is a module tree similar to filesystem:
Paths
To refer to an entity we can use absolute or relative paths.
We separate identifiers by ::
.
Example:
super
acts like ..
in Unix filesystems. We can use it to go up a module.
Encapsulation
-
All entities are private by default.
-
The privacy rules apply to structs, enums, functions, methods, and modules.
-
Items in a parent module cannot use the privte items inside child modules.
-
items in child modules can use items in their ancestor modules.
-
sibling items can access each other.
-
items can be made public with the
pub
keyword. -
struct can be made public, but its fields will stay private unless they are individually made public:
-
all enum’s options are public if enum itself is public.
Importing
The use
keyword brings a path into the local scope so we don’t have to repeat
paths all the time.
Example:
use
is like a symbolic link in a filesystem.
Relative paths can be used with use
as well.
The imported entities may be re-exported with the use of pub use
:
Changing names
If there are entities with the same names (e.g. two structs) we can’t import them both directly. Instead, we should import their containing modules.
We could also change name of an imported entity using the as
keyword:
Importing all
The *
(glob) operator allows us to bring in all items from some module:
Re-exporting
Sometimes having a deep structure of types is good for the author of the crate, but troublesome for the users of the crate. Things can be reexported to change the way how they are visible outside.
The UsefulType
is available from the level of the file where we put that
declaration. It will be also visible in the documentation of our crate.