Rust - First Program
Overview
Estimated time: 20–30 minutes
Write, compile, and run your first Rust program. Learn about the main function, the println! macro, and basic program structure. We'll create both a simple standalone program and a cargo project.
Learning Objectives
- Write and run your first "Hello, World!" program in Rust.
- Understand the structure of a basic Rust program.
- Learn the difference between compiling directly with rustc and using cargo.
- Explore the println! macro and string formatting basics.
Prerequisites
Your First Rust Program
Creating main.rs
Create a new file called main.rs
and add the following code:
fn main() {
println!("Hello, World!");
}
Understanding the Code
fn main()
- The main function, entry point of every Rust programprintln!
- A macro (note the!
) that prints text to the console"Hello, World!"
- A string literal{}
- Curly braces define the function body
Compiling and Running
rustc main.rs
./main # On Windows: main.exe
Expected Output:
Hello, World!
Creating a Cargo Project
Using cargo new
For real projects, use cargo instead of rustc directly:
cargo new hello_world
cd hello_world
This creates the following structure:
hello_world/
├── Cargo.toml
└── src/
└── main.rs
Examining Cargo.toml
[package]
name = "hello_world"
version = "0.1.0"
edition = "2021"
# See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html
[dependencies]
The Default main.rs
fn main() {
println!("Hello, world!");
}
Running with Cargo
cargo run
Expected Output:
Compiling hello_world v0.1.0 (/path/to/hello_world)
Finished dev [unoptimized + debuginfo] target(s) in 0.35s
Running `target/debug/hello_world`
Hello, world!
Exploring the println! Macro
Basic Text Output
fn main() {
println!("Welcome to Rust!");
println!("This is line 2");
println!("This is line 3");
}
Expected Output:
Welcome to Rust!
This is line 2
This is line 3
String Formatting with Variables
fn main() {
let name = "Alice";
let age = 30;
println!("Hello, {}!", name);
println!("You are {} years old", age);
println!("Hello, {}, you are {} years old", name, age);
}
Expected Output:
Hello, Alice!
You are 30 years old
Hello, Alice, you are 30 years old
Positional and Named Arguments
fn main() {
// Positional arguments
println!("{0} is from {1} and {0} likes {2}", "John", "Canada", "hockey");
// Named arguments
println!("{name} is {age} years old", name = "Bob", age = 25);
// Mixed
println!("{}, {job} from {}", "Carol", "Denver", job = "engineer");
}
Expected Output:
John is from Canada and John likes hockey
Bob is 25 years old
Carol, engineer from Denver
Formatting Numbers
fn main() {
let pi = 3.14159;
let large_number = 1234567;
println!("Pi: {}", pi);
println!("Pi with 2 decimals: {:.2}", pi);
println!("Large number: {}", large_number);
println!("With thousand separators: {:,}", large_number);
println!("As hex: {:x}", large_number);
println!("As binary: {:b}", large_number);
}
Expected Output:
Pi: 3.14159
Pi with 2 decimals: 3.14
Large number: 1234567
With thousand separators: 1,234,567
As hex: 12d687
As binary: 100101101011010000111
Different Types of Rust Programs
Binary vs Library Projects
Binary Project (has main.rs)
cargo new my_app # Creates binary project
Library Project (has lib.rs)
cargo new my_lib --lib # Creates library project
Multiple Binary Targets
You can have multiple binaries in one project:
my_project/
├── Cargo.toml
├── src/
│ ├── main.rs # Primary binary
│ └── lib.rs # Library code
└── src/bin/
├── helper.rs # Secondary binary
└── tool.rs # Another binary
# Run different binaries
cargo run # Runs main.rs
cargo run --bin helper # Runs helper.rs
cargo run --bin tool # Runs tool.rs
Understanding Rust Syntax Basics
Function Declaration
fn function_name() {
// Function body
}
fn function_with_params(name: &str, age: i32) {
println!("Name: {}, Age: {}", name, age);
}
Variable Declaration
fn main() {
let message = "Hello"; // Immutable by default
let mut counter = 0; // Mutable variable
println!("{}", message);
counter += 1;
println!("Counter: {}", counter);
}
Expected Output:
Hello
Counter: 1
Type Annotations
fn main() {
let x: i32 = 42; // 32-bit integer
let y: f64 = 3.14; // 64-bit float
let is_rust_awesome: bool = true; // boolean
let letter: char = 'R'; // character
println!("Number: {}", x);
println!("Float: {}", y);
println!("Boolean: {}", is_rust_awesome);
println!("Character: {}", letter);
}
Expected Output:
Number: 42
Float: 3.14
Boolean: true
Character: R
Program Structure Examples
Simple Calculator
fn main() {
let a = 10;
let b = 5;
println!("Addition: {} + {} = {}", a, b, a + b);
println!("Subtraction: {} - {} = {}", a, b, a - b);
println!("Multiplication: {} * {} = {}", a, b, a * b);
println!("Division: {} / {} = {}", a, b, a / b);
}
Expected Output:
Addition: 10 + 5 = 15
Subtraction: 10 - 5 = 5
Multiplication: 10 * 5 = 50
Division: 10 / 5 = 2
Personal Information Display
fn main() {
let first_name = "John";
let last_name = "Doe";
let age = 28;
let height = 5.9;
let is_student = false;
println!("=== Personal Information ===");
println!("Name: {} {}", first_name, last_name);
println!("Age: {} years old", age);
println!("Height: {} feet", height);
println!("Student: {}", if is_student { "Yes" } else { "No" });
println!("=============================");
}
Expected Output:
=== Personal Information ===
Name: John Doe
Age: 28 years old
Height: 5.9 feet
Student: No
=============================
Common Beginner Mistakes
Forgetting Semicolons
Incorrect:
fn main() {
println!("Hello") // Missing semicolon
}
Error:
error: expected `;`, found `}`
Correct:
fn main() {
println!("Hello"); // Semicolon added
}
Wrong Function Name
Incorrect:
fn Main() { // Capital M
println!("Hello");
}
Error:
error: `main` function not found in crate
Correct:
fn main() { // lowercase main
println!("Hello");
}
Using print instead of println!
Less ideal (no newline):
fn main() {
print!("Hello ");
print!("World");
}
Output:
Hello World
Better (with newlines):
fn main() {
println!("Hello ");
println!("World");
}
Output:
Hello
World
Build Process Understanding
What Happens During Compilation
- Parsing: Rust code is parsed into an Abstract Syntax Tree (AST)
- Type Checking: The compiler ensures all types are correct
- Borrow Checking: Memory safety is verified
- Optimization: Code is optimized for performance
- Code Generation: Machine code is generated
Debug vs Release Builds
# Debug build (default)
cargo build
cargo run
# Release build (optimized)
cargo build --release
cargo run --release
Debugging Your First Programs
Adding Debug Information
fn main() {
let x = 42;
println!("Debug info: x = {:?}", x);
let numbers = vec![1, 2, 3];
println!("Debug info: numbers = {:?}", numbers);
}
Expected Output:
Debug info: x = 42
Debug info: numbers = [1, 2, 3]
Using dbg! Macro
fn main() {
let x = 5;
let y = dbg!(x * 2); // Shows the calculation
println!("Result: {}", y);
}
Expected Output:
[src/main.rs:3] x * 2 = 10
Result: 10
Next Steps
Now that you can write and run basic Rust programs:
- Experiment with different println! formatting options
- Create multiple cargo projects to practice
- Try the debug macros dbg! and {:?}
- Practice with different data types
- Explore cargo commands like
cargo check
andcargo build --release
Common Pitfalls
- Case sensitivity:
main
notMain
,println!
notPrintLn!
- Missing semicolons: Most statements need semicolons in Rust
- Forgetting the exclamation mark:
println!
is a macro, not a function - String vs str confusion: We'll cover this in detail later
Checks for Understanding
- What is the entry point function for every Rust program?
- What's the difference between
print!
andprintln!
? - How do you create a new cargo project?
- What does the
{}
placeholder do inprintln!
? - How do you compile and run a single Rust file without cargo?
Answers
fn main()
- the main functionprint!
doesn't add a newline,println!
doescargo new project_name
- It's a placeholder for inserting values into the string
rustc filename.rs
then run the executable