D1.0 What This Teaches
Cargo's examples/ directory lets you write standalone runnable programs that
import from your library crate, without mixing that code into src/main.rs
or the test suite. This tutorial covers:
- What the
examples/ directory is and why it exists
- Single-file examples that import from the library
- Multi-file examples using a local
mod inside examples/
- The
cargo run --example and cargo build --examples commands
- How examples access the library crate by name
D1.1 Why examples/?
A library crate has no entry point - you cannot cargo run it directly. The
examples/ directory solves this: each file in it compiles as its own binary
that can use any public item from the library. This keeps demonstrations out
of the test suite (which tests correctness) and out of src/main.rs (which
would only allow one entry point).
Examples are also the conventional place to show how a library is meant to be used -
they serve as living documentation.
D1.2 Project Layout
Demonstrations/
├── Cargo.toml
├── src/
│ └── lib.rs ← the library: add, clamp, word_count, Circle, Rectangle
├── examples/
│ ├── basic.rs ← single-file example
│ ├── words.rs ← single-file example
│ ├── shapes.rs ← single-file example
│ └── shapes_multifile/
│ ├── main.rs ← entry point for the multi-file example
│ └── geometry.rs ← local module used only by this example
A single-file example lives directly in examples/. A multi-file example
gets its own subdirectory; Cargo looks for main.rs inside it as the entry
point.
D1.3 The Library - src/lib.rs
All items examples import must be pub:
// Demonstrations/lib.rs - small public library used by examples in examples/.
pub fn add(a: i32, b: i32) -> i32 { a + b }
pub fn clamp(value: i32, lo: i32, hi: i32) -> i32 {
if value < lo { lo } else if value > hi { hi } else { value }
}
pub fn word_count(s: &str) -> usize {
s.split_whitespace().count()
}
pub fn unique_words(s: &str) -> Vec<&str> {
let mut words: Vec<&str> = s.split_whitespace().collect();
words.sort_unstable();
words.dedup();
words
}
#[derive(Debug)]
pub struct Circle {
pub radius: f64,
}
impl Circle {
pub fn new(radius: f64) -> Self { Circle { radius } }
pub fn area(&self) -> f64 { std::f64::consts::PI * self.radius * self.radius }
pub fn circumference(&self) -> f64 { 2.0 * std::f64::consts::PI * self.radius }
}
#[derive(Debug)]
pub struct Rectangle {
pub width: f64,
pub height: f64,
}
impl Rectangle {
pub fn new(width: f64, height: f64) -> Self { Rectangle { width, height } }
pub fn area(&self) -> f64 { self.width * self.height }
pub fn perimeter(&self) -> f64 { 2.0 * (self.width + self.height) }
pub fn is_square(&self) -> bool { self.width == self.height }
}
The crate name comes from Cargo.toml: name = "demonstrations".
That name is what examples use in their use statements.
D1.4 Single-File Example: basic.rs
// basic.rs - demonstrates add and clamp from the demonstrations library.
// Run with: cargo run --example basic
use demonstrations::{add, clamp};
fn main() {
println!("=== basic example ===");
let sum = add(7, 3);
println!("add(7, 3) = {sum}");
let clamped_high = clamp(25, 0, 20);
let clamped_low = clamp(-5, 0, 20);
let clamped_mid = clamp(10, 0, 20);
println!("clamp(25, 0, 20) = {clamped_high}");
println!("clamp(-5, 0, 20) = {clamped_low}");
println!("clamp(10, 0, 20) = {clamped_mid}");
}
use demonstrations::{add, clamp} imports by the crate name defined in
Cargo.toml. Run it with cargo run --example basic.
D1.5 Single-File Example: words.rs
// words.rs - demonstrates word_count and unique_words from the demonstrations library.
// Run with: cargo run --example words
use demonstrations::{word_count, unique_words};
fn main() {
println!("=== words example ===");
let text = "the quick brown fox jumps over the lazy dog the fox";
println!("text: \"{text}\"");
println!("word_count: {}", word_count(text));
println!("unique words: {:?}", unique_words(text));
}
D1.6 Single-File Example: shapes.rs
// shapes.rs - demonstrates Circle and Rectangle from the demonstrations library.
// Run with: cargo run --example shapes
use demonstrations::{Circle, Rectangle};
fn main() {
println!("=== shapes example ===");
let c = Circle::new(5.0);
println!("Circle r=5:");
println!(" area = {:.4}", c.area());
println!(" circumference = {:.4}", c.circumference());
let r = Rectangle::new(4.0, 6.0);
println!("Rectangle 4x6:");
println!(" area = {:.1}", r.area());
println!(" perimeter = {:.1}", r.perimeter());
println!(" is_square = {}", r.is_square());
let sq = Rectangle::new(5.0, 5.0);
println!("Rectangle 5x5:");
println!(" is_square = {}", sq.is_square());
}
D1.7 Multi-File Example: shapes_multifile
When an example needs helper modules, put it in a subdirectory. Cargo uses
examples/shapes_multifile/main.rs as the entry point and compiles the
subdirectory as a mini-crate:
// shapes_multifile/main.rs - multi-file example showing local module use within examples/.
// Run with: cargo run --example shapes_multifile
mod geometry;
use demonstrations::{Circle, Rectangle};
fn main() {
println!("=== shapes_multifile example ===");
let shapes_c = vec![Circle::new(1.0), Circle::new(3.0), Circle::new(5.0)];
println!("Circles:");
for c in &shapes_c {
geometry::print_circle_report(c);
}
let shapes_r = vec![
Rectangle::new(2.0, 8.0),
Rectangle::new(5.0, 5.0),
Rectangle::new(3.0, 7.0),
];
println!("Rectangles:");
for r in &shapes_r {
geometry::print_rect_report(r);
}
}
mod geometry; pulls in geometry.rs from the same
shapes_multifile/ directory. That module can also use items from the
library:
// geometry.rs - local helper module for the shapes_multifile example.
use demonstrations::{Circle, Rectangle};
pub fn print_circle_report(c: &Circle) {
println!(" {:?}", c);
println!(" area = {:.4}", c.area());
println!(" circumference = {:.4}", c.circumference());
}
pub fn print_rect_report(r: &Rectangle) {
println!(" {:?}", r);
println!(" area = {:.2}", r.area());
println!(" perimeter = {:.2}", r.perimeter());
println!(" is_square = {}", r.is_square());
}
D1.8 cargo Commands
| Command | What it does |
cargo run --example basic | Compile and run examples/basic.rs |
cargo run --example words | Compile and run examples/words.rs |
cargo run --example shapes_multifile | Compile and run examples/shapes_multifile/main.rs |
cargo build --examples | Build all examples without running them |
cargo test | Runs unit and integration tests; does NOT run examples |
Example binaries land in target/debug/examples/. You can run them directly
from there if you need to pass arguments that cargo run would interpret
as its own flags.
D1.9 How Examples Access the Library
Cargo automatically links each example against the library defined in the same
Cargo.toml. The import path is the crate name from Cargo.toml:
[package]
name = "demonstrations" ← this becomes the crate name in use statements
use demonstrations::add; // works in any file under examples/
Only pub items are accessible. Private functions, fields, and modules are
invisible to examples just as they would be to an external crate.
D1.10 Examples vs. Tests vs. main.rs
| Location | Purpose | Run with |
| examples/ | Demonstrate library usage; living documentation | cargo run --example <name> |
| tests/ | Integration tests; verify public API behavior | cargo test |
| #[cfg(test)] mod tests | Unit tests; verify internal logic | cargo test |
| src/main.rs | Binary entry point; one program per package | cargo run |
D1.11 Expected Outputs
cargo run --example basic
=== basic example ===
add(7, 3) = 10
clamp(25, 0, 20) = 20
clamp(-5, 0, 20) = 0
clamp(10, 0, 20) = 10
cargo run --example words
=== words example ===
text: "the quick brown fox jumps over the lazy dog the fox"
word_count: 11
unique words: ["brown", "dog", "fox", "jumps", "lazy", "over", "quick", "the"]
cargo run --example shapes
=== shapes example ===
Circle r=5:
area = 78.5398
circumference = 31.4159
Rectangle 4x6:
area = 24.0
perimeter = 20.0
is_square = false
Rectangle 5x5:
is_square = true
cargo run --example shapes_multifile
=== shapes_multifile example ===
Circles:
Circle { radius: 1.0 }
area = 3.1416
circumference = 6.2832
Circle { radius: 3.0 }
area = 28.2743
circumference = 18.8496
Circle { radius: 5.0 }
area = 78.5398
circumference = 31.4159
Rectangles:
Rectangle { width: 2.0, height: 8.0 }
area = 16.00
perimeter = 20.00
is_square = false
Rectangle { width: 5.0, height: 5.0 }
area = 25.00
perimeter = 20.00
is_square = true
Rectangle { width: 3.0, height: 7.0 }
area = 21.00
perimeter = 20.00
is_square = false
D1.12 Exercise
Exercise
- Add a
pub fn median(values: &mut Vec<f64>) -> Option<f64>
function to lib.rs. It should sort the vec in place and return
the middle element (or the average of the two middle elements for even-length
vecs). Return None for an empty vec.
- Write a new single-file example
examples/stats.rs that creates
several Vec<f64> values, calls median on each,
and prints the result. Run it with cargo run --example stats.
- Add a multi-file example
examples/report/ with a
main.rs entry point and a format.rs helper module.
format.rs should contain a pub fn row(label: &str, value: f64)
that prints a padded label-value pair. Call it from main.rs to
print a formatted summary of several shapes.
D1.13 Common Mistakes
Forgetting lib.rs - examples import a library, not main.rs
If your package only has src/main.rs, there is no library crate for
examples to import. Add src/lib.rs and move the shared code there. A
package can have both main.rs and lib.rs.
Wrong crate name in use statements
use my_project::add; // error if Cargo.toml says name = "demonstrations"
use demonstrations::add; // correct
The name in the use path must exactly match the name field
in [package] of Cargo.toml. Hyphens in the name become
underscores: my-lib in Cargo.toml is my_lib in code.
Naming a single-file example the same as a subdirectory example
examples/shapes.rs ← single-file example named "shapes"
examples/shapes/main.rs ← multi-file example also named "shapes" ← conflict
Each example must have a unique name. Use distinct names for single-file and
multi-file examples. Cargo will error if both exist.
Expecting cargo test to run examples
cargo test runs unit tests (#[test]) and integration tests
(tests/). It does not run examples. Use
cargo run --example <name> or
cargo build --examples to compile examples.
Accessing private items from examples
use demonstrations::internal_helper; // error: function is not pub
Examples are external callers - they can only access pub items. Mark
anything the examples need as pub in lib.rs.
D1.14 Key Terms
| Term | Meaning |
| examples/ | Cargo-recognized directory; each file (or subdirectory with main.rs) compiles as a standalone binary |
| cargo run --example <name> | Compile and run the named example |
| cargo build --examples | Build all examples without running |
| crate name | The name field in [package] of Cargo.toml; used in use paths |
| single-file example | One .rs file directly in examples/; the filename is the example name |
| multi-file example | A subdirectory in examples/ with main.rs as the entry point |
| pub | Visibility modifier required for any item accessible from examples or external crates |
| lib.rs | Root of the library crate; must exist for examples to import anything |