Learn Rust Programming: A Beginner’s Guide with Examples

by Didin J. on Jun 12, 2025 Learn Rust Programming: A Beginner’s Guide with Examples

Learn Rust programming with clear examples and a beginner-friendly guide. Build real apps, understand ownership, and master Rust's powerful features.

Rust is a fast, reliable, and memory-safe programming language that’s gaining widespread adoption for systems programming, web development, embedded systems, and beyond. In this beginner’s guide, we’ll introduce the fundamentals of Rust and walk through simple examples to help you write your first Rust program with confidence.


Why Learn Rust?

Rust stands out for its unique combination of performance and safety. It compiles to native code, offers zero-cost abstractions, and enforces memory safety without a garbage collector. Here’s why developers love Rust:

  • Memory Safety: Prevents null pointer dereferencing and data races.

  • Speed: As fast as C and C++.

  • Concurrency: Built-in support for multithreading.

  • Developer Tools: Great compiler error messages and an excellent package manager (cargo).

  • Growing Ecosystem: Used by companies like Mozilla, Dropbox, Amazon, and Microsoft.


Setting Up the Rust Environment

To start coding in Rust, first install the official toolchain:

Step 1: Install Rust

Run the following command in your terminal:

curl --proto '=https' --tlsv1.2 -sSf https://sh.rustup.rs | sh

After installation, restart your terminal and verify:

rustc --version
cargo --version

Step 2: Create a New Rust Project

cargo new hello_rust
cd hello_rust

This generates a basic Rust project with a main.rs file inside src/.


Your First Rust Program

Let’s explore a simple “Hello, World!” program:

fn main() {
    println!("Hello, Rust!");
}

To run it:

cargo run

Breakdown

  • fn main() is the entry point.

  • println! is a macro for printing text to the console.

  • Semicolons ; end statements in Rust.


Understanding Rust Variables

Rust variables are immutable by default. Use mut to make them mutable.

fn main() {
    let x = 5;
    println!("x is {}", x);

    let mut y = 10;
    println!("y is {}", y);
    y = 20;
    println!("now y is {}", y);
}


Data Types in Rust

Rust is statically typed. Common types include:

  • Integers: i32, u64, etc.

  • Floats: f32, f64

  • Boolean: bool

  • Character: char

  • Tuple and Array

Example:

fn main() {
    let tup: (i32, f64, char) = (1, 3.14, 'R');
    let arr = [1, 2, 3, 4, 5];

    println!("First tuple item: {}", tup.0);
    println!("Array length: {}", arr.len());
}


Control Flow in Rust

Rust supports if, else, match, loop, while, and for.

if and else

fn main() {
    let number = 7;

    if number < 10 {
        println!("Less than 10");
    } else {
        println!("10 or more");
    }
}

match Statement

fn main() {
    let num = 2;

    match num {
        1 => println!("One"),
        2 => println!("Two"),
        _ => println!("Something else"),
    }
}


Functions in Rust

Functions are declared using fn:

fn greet(name: &str) {
    println!("Hello, {}!", name);
}

fn main() {
    greet("Rust");
}

Functions can return values:

fn add(x: i32, y: i32) -> i32 {
    x + y
}


Ownership and Borrowing

Rust’s most unique feature is its ownership model, which helps manage memory safely.

Ownership Example

fn main() {
    let s1 = String::from("hello");
    let s2 = s1; // ownership moved
    // println!("{}", s1); // error: s1 no longer valid
}


Error Handling

Rust uses Result and Option types instead of exceptions.

use std::fs::File;

fn main() {
    let file = File::open("hello.txt");

    match file {
        Ok(f) => println!("File opened successfully"),
        Err(e) => println!("Error: {}", e),
    }
}


Advanced Rust Concepts (For the Curious Beginner)

Once you're comfortable with the basics, Rust offers more powerful abstractions that are both safe and efficient.

Structs and Enums

Structs

Structs let you define custom types:

struct User {
    username: String,
    age: u8,
}

fn main() {
    let user1 = User {
        username: String::from("djamware"),
        age: 30,
    };

    println!("Username: {}", user1.username);
}

Enums

Enums are perfect for types that can be one of several variants:

enum Message {
    Quit,
    Move { x: i32, y: i32 },
    Write(String),
}

fn main() {
    let msg = Message::Write(String::from("Hello"));
    
    match msg {
        Message::Quit => println!("Quit"),
        Message::Move { x, y } => println!("Move to ({}, {})", x, y),
        Message::Write(text) => println!("Text: {}", text),
    }
}

Traits and Generics

Rust doesn’t have traditional OOP classes, but you can achieve polymorphism with traits.

trait Greet {
    fn greet(&self);
}

struct Person;
struct Robot;

impl Greet for Person {
    fn greet(&self) {
        println!("Hi! I'm a person.");
    }
}

impl Greet for Robot {
    fn greet(&self) {
        println!("Beep boop. I'm a robot.");
    }
}

fn say_hello<T: Greet>(greeter: T) {
    greeter.greet();
}

Lifetimes (Introduction)

Lifetimes ensure references are valid. Here’s a simple example:

fn longest<'a>(x: &'a str, y: &'a str) -> &'a str {
    if x.len() > y.len() {
        x
    } else {
        y
    }
}

This function returns a reference that’s valid as long as both inputs are.


Build a Simple CLI Project in Rust

Let’s use your new skills to build a command-line to-do list app using Rust.

Step 1: Create a New Project

cargo new todo_cli
cd todo_cli

Step 2: Update Cargo.toml

Add dependencies:

[dependencies]
serde = { version = "1.0", features = ["derive"] }
serde_json = "1.0"

Step 3: Basic Task Struct

use serde::{Serialize, Deserialize};

#[derive(Serialize, Deserialize)]
pub struct Task {
    pub(crate) title: String,
    pub(crate) done: bool,
}

Step 4: Add Functionality

Create, list, and toggle tasks.

use serde::{ Serialize, Deserialize };
use std::fs::{ OpenOptions };
use std::io::{ Read, Write };

#[derive(Serialize, Deserialize)]
pub struct Task {
    pub(crate) title: String,
    pub(crate) done: bool,
}

pub fn load_tasks() -> Vec<Task> {
    let mut file = OpenOptions::new()
        .read(true)
        .create(true)
        .open("tasks.json")
        .expect("Failed to open file");

    let mut content = String::new();
    file.read_to_string(&mut content).unwrap();
    if content.is_empty() {
        return vec![];
    }

    serde_json::from_str(&content).unwrap()
}

pub fn save_tasks(tasks: &[Task]) {
    let json = serde_json::to_string_pretty(tasks).unwrap();
    let mut file = OpenOptions::new().write(true).truncate(true).open("tasks.json").unwrap();
    file.write_all(json.as_bytes()).unwrap();
}

Step 5: Main CLI Logic

mod task;
use task::{ Task, load_tasks, save_tasks };

fn main() {
    let args: Vec<String> = std::env::args().collect();
    let mut tasks = load_tasks();

    match args.get(1).map(|s| s.as_str()) {
        Some("add") => {
            let title = args.get(2).expect("No task title provided");
            tasks.push(Task {
                title: title.clone(),
                done: false,
            });
            save_tasks(&tasks);
            println!("Task added.");
        }
        Some("list") => {
            for (i, task) in tasks.iter().enumerate() {
                let status = if task.done { "✓" } else { " " };
                println!("[{}] {}: {}", status, i, task.title);
            }
        }
        Some("done") => {
            let index: usize = args.get(2).unwrap().parse().unwrap();
            if let Some(task) = tasks.get_mut(index) {
                task.done = true;
                save_tasks(&tasks);
                println!("Task marked as done.");
            }
        }
        _ => {
            println!("Usage: todo_cli [add|list|done] [task]");
        }
    }
}

Step 6: Run It

cargo run -- add "Learn Rust"
cargo run -- list
cargo run -- done 0

Learn Rust Programming: A Beginner’s Guide with Examples - todo cli

What’s Next?

You’ve now:

  • Written your first Rust programs

  • Learned core concepts: variables, ownership, functions, structs, enums

  • Built a basic CLI app using external crates


Conclusion

Rust may have a steep learning curve at first, but its powerful features and safety guarantees make it well worth the effort. In this beginner’s guide, you’ve explored the core concepts of Rust—from variables, control flow, and functions to ownership, structs, and enums. You’ve also taken your first steps toward building real-world applications by creating a simple command-line to-do app.

What sets Rust apart is its focus on memory safety without a garbage collector, and its ability to catch many bugs at compile time. These qualities make it a top choice for systems programming, high-performance applications, and even web backends.

Whether you're coming from JavaScript, Python, or C++, learning Rust can sharpen your skills and change the way you think about programming.

You're now equipped to:

  • Understand the Rust syntax and core concepts

  • Write and run basic Rust programs

  • Start experimenting with real-world projects

Next up? Dive deeper into Rust's ecosystem—build a REST API, try async programming, or explore frontend frameworks like Yew. The Rust journey has just begun, and you're off to a strong start.

You can get the full source code of the Basic Rust and Todo CLI App.

That is just the basics. If you need more deep learning about the Rust language and frameworks, you can take the following cheap course:

Thanks!