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

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

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

  1. Parsing: Rust code is parsed into an Abstract Syntax Tree (AST)
  2. Type Checking: The compiler ensures all types are correct
  3. Borrow Checking: Memory safety is verified
  4. Optimization: Code is optimized for performance
  5. 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:

  1. Experiment with different println! formatting options
  2. Create multiple cargo projects to practice
  3. Try the debug macros dbg! and {:?}
  4. Practice with different data types
  5. Explore cargo commands like cargo check and cargo build --release

Common Pitfalls

Checks for Understanding

  1. What is the entry point function for every Rust program?
  2. What's the difference between print! and println!?
  3. How do you create a new cargo project?
  4. What does the {} placeholder do in println!?
  5. How do you compile and run a single Rust file without cargo?

Answers

  1. fn main() - the main function
  2. print! doesn't add a newline, println! does
  3. cargo new project_name
  4. It's a placeholder for inserting values into the string
  5. rustc filename.rs then run the executable

← PreviousNext →