12. Modules, crates, and visibility
myapp/
├── Cargo.toml
└── src/
├── main.rs // crate root of the binary
├── lib.rs // crate root of the library (a package can have both)
├── config.rs // mod config;
└── net/
├── mod.rs // or net.rs next to a net/ directory
└── frame.rs // mod frame; inside net
mod net {
pub mod frame {
pub struct Frame { pub len: u32, checksum: u32 } // `checksum` is private to this module
impl Frame {
pub fn new(len: u32) -> Self { Self { len, checksum: len ^ 0xFFFF } }
pub fn valid(&self) -> bool { self.checksum == self.len ^ 0xFFFF }
}
pub(crate) fn internal_helper() -> u8 { 7 } // visible anywhere in THIS crate only
}
pub use frame::Frame; // re-export: callers write net::Frame
}
use net::Frame;
fn main() {
let f = Frame::new(42);
// let bad = net::frame::Frame { len: 1, checksum: 0 }; // error[E0451]: field `checksum` is private
println!("{} {} {}", f.len, f.valid(), net::frame::internal_helper());
}
- Everything is private by default. Use
pub, pub(crate), or
pub(super) to widen visibility. Go uses capitalization for the same
purpose (Go §11.1);
C uses static (C §13.1).
- A private field means outside code cannot construct the struct with a
literal. It has to go through your constructor, which can enforce
invariants. This is how
String guarantees valid UTF-8.
- Features (
[features] in Cargo.toml) are compile-time flags,
like C's #ifdef, applied per crate: #[cfg(feature = "tls")].