Site

Demonstrations — Using the examples/ Folder

Tutorial D1.0  •  Rust / Learn / Demonstrations

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:

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

CommandWhat it does
cargo run --example basicCompile and run examples/basic.rs
cargo run --example wordsCompile and run examples/words.rs
cargo run --example shapes_multifileCompile and run examples/shapes_multifile/main.rs
cargo build --examplesBuild all examples without running them
cargo testRuns 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

LocationPurposeRun with
examples/Demonstrate library usage; living documentationcargo run --example <name>
tests/Integration tests; verify public API behaviorcargo test
#[cfg(test)] mod testsUnit tests; verify internal logiccargo test
src/main.rsBinary entry point; one program per packagecargo 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

TermMeaning
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 --examplesBuild all examples without running
crate nameThe name field in [package] of Cargo.toml; used in use paths
single-file exampleOne .rs file directly in examples/; the filename is the example name
multi-file exampleA subdirectory in examples/ with main.rs as the entry point
pubVisibility modifier required for any item accessible from examples or external crates
lib.rsRoot of the library crate; must exist for examples to import anything