Rust for Beginners: Dive into coding with these 5 Projects to boost your skills

January 20249 min read
Rust for Beginners: Dive into coding with these 5 Projects to boost your skills

Welcome to the thrilling world of Rust programming! Whether you're a coding enthusiast embarking on your programming journey or a seasoned developer eager to add a new language to your arsenal, Rust offers an exciting playground for honing your skills. In this article, I'll guide you through an engaging exploration, providing you with five hands-on projects designed specifically for beginners.

Rust isn't just a programming language; it's a mindset—a commitment to performance, safety, and concurrency. As you navigate through these carefully curated projects, you'll not only grasp the fundamentals of Rust but also witness firsthand its power in creating efficient, reliable, and high-performance code.

Each project serves as a stepping stone, gradually introducing you to Rust's syntax, principles, and unique features. From simple yet impactful tasks to more complex challenges, these projects are crafted to provide a well-rounded learning experience. So, buckle up and get ready to dive headfirst into the world of Rust, where your coding adventure begins!

Without further ado, let's explore "Rust for Beginners: Dive into Coding with These 5 Projects to boost your skills" and uncover the exciting possibilities that await you on your Rustic coding journey.

To-Do List App

Building a To-Do List application in Rust is a great way to get hands-on experience with the language and its ecosystem. Below is a simple step-by-step guide to help you get started with creating a basic console-based To-Do List application in Rust.

Step 1: Set Up Your Rust Environment

If you haven't installed Rust, you can do so by following the instructions on the official Rust website: https://www.rust-lang.org/tools/install.

Step 2: Create a New Rust Project

Open a terminal and run the following commands:

# Create a new Rust project
$ cargo new todo_app
  
# Navigate to the project directory
$ cd todo_app

Step 3: Define Your To-Do Item Structure

Edit the src/main.rs file to define the structure for your To-Do items:

Define Your To-Do Item Structure

Step 4: Implement To-Do List Operations

Update src/main.rs to implement basic operations like adding, listing, and completing To-Do items:

// src/main.rs

use std::io;

struct TodoItem {
    id: u64,
    title: String,
    completed: bool,
}

struct TodoList {
    items: Vec<TodoItem>,
}

impl TodoList {
    fn new() -> TodoList {
        TodoList { items: Vec::new() }
    }

    fn add_item(&mut self, title: String) {
        let id = self.items.len() as u64 + 1;
        let new_item = TodoItem {
            id,
            title: title.clone(),
            completed: false,
        };
        self.items.push(new_item);
        println!("Added: {}", title);
    }

    fn list_items(&self) {
        if self.items.is_empty() {
            println!("Your to-do list is empty.");
        } else {
            println!("Your to-do list:");
            for item in &self.items {
                let status = if item.completed { "[X]" } else { "[ ]" };
                println!("{} {} - {}", status, item.id, item.title);
            }
        }
    }

    fn complete_item(&mut self, id: u64) {
        if let Some(item) = self.items.iter_mut().find(|i| i.id == id) {
            item.completed = true;
            println!("Completed: {}", item.title);
        } else {
            println!("Item with ID {} not found.", id);
        }
    }
}

fn main() {
    let mut todo_list = TodoList::new();

    loop {
        println!("1. Add Item");
        println!("2. List Items");
        println!("3. Complete Item");
        println!("4. Exit");

        let mut choice = String::new();
        io::stdin().read_line(&mut choice).expect("Failed to read line");
        let choice: u32 = match choice.trim().parse() {
            Ok(num) => num,
            Err(_) => continue,
        };

        match choice {
            1 => {
                println!("Enter the title of the new item:");
                let mut title = String::new();
                io::stdin().read_line(&mut title).expect("Failed to read line");
                todo_list.add_item(title.trim().to_string());
            }
            2 => {
                todo_list.list_items();
            }
            3 => {
                println!("Enter the ID of the completed item:");
                let mut id = String::new();
                io::stdin().read_line(&mut id).expect("Failed to read line");
                let id: u64 = match id.trim().parse() {
                    Ok(num) => num,
                    Err(_) => continue,
                };
                todo_list.complete_item(id);
            }
            4 => {
                println!("Exiting the program.");
                break;
            }
            _ => {
                println!("Invalid choice. Please enter a number between 1 and 4.");
            }
        }
    }
}

Step 5: Run Your To-Do List Application

Run your application using:

cargo run

Follow the on-screen instructions to add, list, and complete To-Do items in your Rust To-Do List application.

Calculator App

Building a basic calculator in Rust is a great way to practice the language and its fundamental concepts.

Step 1: Set Up Your Rust Environment

Step 2: Create a New Rust Project

# Create a new Rust project
$ cargo new calculator_app
$ cd calculator_app

Step 3: Implement the Calculator Logic

Edit the src/main.rs file to implement the calculator logic:

// src/main.rs

use std::io;

fn main() {
    loop {
        println!("Simple Calculator");
        println!("1. Addition");
        println!("2. Subtraction");
        println!("3. Multiplication");
        println!("4. Division");
        println!("5. Exit");

        let mut choice = String::new();
        io::stdin().read_line(&mut choice).expect("Failed to read line");
        let choice: u32 = match choice.trim().parse() {
            Ok(num) => num,
            Err(_) => continue,
        };

        if choice == 5 {
            println!("Exiting the calculator.");
            break;
        }

        println!("Enter the first number:");
        let mut num1 = String::new();
        io::stdin().read_line(&mut num1).expect("Failed to read line");
        let num1: f64 = match num1.trim().parse() {
            Ok(num) => num,
            Err(_) => {
                println!("Invalid input. Please enter a valid number.");
                continue;
            }
        };

        println!("Enter the second number:");
        let mut num2 = String::new();
        io::stdin().read_line(&mut num2).expect("Failed to read line");
        let num2: f64 = match num2.trim().parse() {
            Ok(num) => num,
            Err(_) => {
                println!("Invalid input. Please enter a valid number.");
                continue;
            }
        };

        match choice {
            1 => {
                let result = num1 + num2;
                println!("Result: {}", result);
            }
            2 => {
                let result = num1 - num2;
                println!("Result: {}", result);
            }
            3 => {
                let result = num1 * num2;
                println!("Result: {}", result);
            }
            4 => {
                if num2 != 0.0 {
                    let result = num1 / num2;
                    println!("Result: {}", result);
                } else {
                    println!("Error: Division by zero.");
                }
            }
            _ => {
                println!("Invalid choice. Please enter a number between 1 and 5.");
            }
        }
    }
}

Step 4: Run Your Calculator

cargo run

Simple Blog Platform

Building a simple blog platform in Rust involves creating a web server, handling HTTP requests, and interacting with a database. Here, I'll guide you through creating a basic blog platform using the Actix web framework and SQLite as the database.

Note that this is a minimal example for learning purposes. In a real-world scenario, you'd want to consider security, user authentication, and additional features.

Step 1: Set Up Your Rust Environment

Step 2: Create a New Rust Project

# Create a new Rust project
$ cargo new new simple_blog
$ cd new simple_blog

Step 3: Add Dependencies to Cargo.toml

Edit the Cargo.toml file to include the necessary dependencies:

[dependencies]
actix-web = "4.0"
actix-rt = "2.5"
sqlx = "0.5"
sqlx-core = "0.5"
sqlx-migrate = "0.5"
sqlx-derive = "0.5"
dotenv = "0.17"

Run cargo build to fetch and build the dependencies.

Step 4: Set Up Your Database

Create a .env file in your project directory with the following content:

DATABASE_URL=sqlite:./blog.db

Step 5: Define the Database Schema

Create a migrations directory and add a file named 20220101000000_init.sql:

-- migrations/20220101000000_init.sql

-- create the posts table
CREATE TABLE posts (
    id INTEGER PRIMARY KEY,
    title TEXT NOT NULL,
    content TEXT NOT NULL
);

Step 6: Set Up Database Connection

Create a src/db.rs file for handling the database connection:

// src/db.rs

use sqlx::sqlite::SqlitePool;
use sqlx::Pool;
use std::env;

pub async fn init_pool() -> Pool<SqlitePool> {
    let database_url = env::var("DATABASE_URL").expect("DATABASE_URL is not set in .env");
    SqlitePool::connect(&database_url)
        .await
        .expect("Failed to connect to the database")
}

Step 7: Implement the Blog Platform

Edit the src/main.rs file with the following code:

// src/main.rs

use actix_web::{web, App, HttpServer, Responder};
use sqlx::sqlite::SqlitePool;
use sqlx::Row;
use dotenv::dotenv;

mod db;

async fn index(pool: web::Data<SqlitePool>) -> impl Responder {
    let mut conn = pool.acquire().await.expect("Failed to acquire a database connection");
    
    let result = sqlx::query!("SELECT id, title, content FROM posts")
        .fetch_all(&mut conn)
        .await
        .expect("Failed to fetch posts from the database");

    let posts: Vec<String> = result
        .iter()
        .map(|row| format!("{}: {}\n{}", row.id, row.title, row.content))
        .collect();

    posts.join("\n")
}

#[actix_web::main]
async fn main() -> std::io::Result<()> {
    dotenv().ok();

    let pool = db::init_pool().await;

    HttpServer::new(move || {
        App::new()
            .app_data(web::Data::new(pool.clone()))
            .route("/", web::get().to(index))
    })
    .bind("127.0.0.1:8080")?
    .run()
    .await
}

Step 8: Run the Application

cargo run

Visit http://127.0.0.1:8080 to see your simple blog platform in action.

This is a basic example, and you can extend it by adding features such as creating, updating, and deleting posts, handling user authentication, and improving the frontend using a front-end framework. Remember to handle errors and ensure security in a production environment.

Weather App

Building a weather app in Rust involves interacting with a weather API to fetch real-time weather data and presenting it to users. Here's a simple example using the Actix web framework and the OpenWeatherMap API.

Step 1: Set Up Your Rust Environment

Step 2: Create a New Rust Project

# Create a new Rust project
$ cargo new weather_app
$ cd weather_app

Step 3: Add Dependencies to Cargo.toml

Edit the Cargo.toml file to include the necessary dependencies:

[dependencies]
actix-web = "4.0"
reqwest = "0.11"
serde = "1.0"
serde_json = "1.0"
dotenv = "0.17"

Run cargo build to fetch and build the dependencies.

Step 4: Set Up Your OpenWeatherMap API Key

Create a .env file in your project directory with the following content:

OPENWEATHERMAP_API_KEY=your_api_key_here

Replace your_api_key_here with your actual OpenWeatherMap API key.

Step 5: Implement the Weather App

Edit the src/main.rs file with the following code:

// src/main.rs

use actix_web::{web, App, HttpServer, HttpResponse};
use reqwest::Client;
use serde::Deserialize;
use std::env;

#[derive(Deserialize)]
struct WeatherResponse {
    main: Main,
    name: String,
}

#[derive(Deserialize)]
struct Main {
    temp: f32,
}

async fn index() -> HttpResponse {
    let api_key = env::var("OPENWEATHERMAP_API_KEY").expect("OPENWEATHERMAP_API_KEY is not set in .env");
    let city = "London"; // You can replace this with the desired city

    let url = format!(
        "http://api.openweathermap.org/data/2.5/weather?q={}&appid={}&units=metric",
        city, api_key
    );

    let response = Client::new().get(&url).send().await;

    match response {
        Ok(res) => {
            let weather_data: WeatherResponse = res.json().await.expect("Failed to parse JSON response");

            let temperature = weather_data.main.temp;
            let city_name = weather_data.name;

            HttpResponse::Ok().body(format!("Weather in {}: {:.1}°C", city_name, temperature))
        }
        Err(_) => HttpResponse::InternalServerError().body("Failed to fetch weather data"),
    }
}

#[actix_web::main]
async fn main() -> std::io::Result<()> {
    dotenv::dotenv().ok();

    HttpServer::new(|| {
        App::new().route("/", web::get().to(index))
    })
    .bind("127.0.0.1:8080")?
    .run()
    .await
}

Step 6: Run the Application

cargo run

Visit http://127.0.0.1:8080 to see the current weather in the specified city.

This serves as a foundation; consider refining it by incorporating user city input, refining error handling, and enhancing the frontend with a robust framework. Prioritize error management and security measures for production readiness.

Budget Manager App

Building a simple budget manager in Rust involves creating a command-line application that allows users to manage their income, expenses, and view the overall budget. Here's a basic example to get you started:

Step 1: Set Up Your Rust Environment

Step 2: Create a New Rust Project

cargo new budget_manager
cd budget_manager

Step 3: Implement the Budget Manager

Edit the src/main.rs file with the following code:

// src/main.rs

use std::io;

struct BudgetManager {
    income: f64,
    expenses: f64,
}

impl BudgetManager {
    fn new() -> Self {
        Self {
            income: 0.0,
            expenses: 0.0,
        }
    }

    fn add_income(&mut self, amount: f64) {
        self.income += amount;
        println!("Income added: ${}", amount);
    }

    fn add_expense(&mut self, amount: f64) {
        self.expenses += amount;
        println!("Expense added: ${}", amount);
    }

    fn view_budget(&self) {
        let balance = self.income - self.expenses;
        println!("Income: ${}", self.income);
        println!("Expenses: ${}", self.expenses);
        println!("Balance: ${}", balance);
    }
}

fn main() {
    let mut budget_manager = BudgetManager::new();

    loop {
        println!("Budget Manager");
        println!("1. Add Income");
        println!("2. Add Expense");
        println!("3. View Budget");
        println!("4. Exit");

        let mut choice = String::new();
        io::stdin().read_line(&mut choice).expect("Failed to read line");
        let choice: u32 = match choice.trim().parse() {
            Ok(num) => num,
            Err(_) => continue,
        };

        match choice {
            1 => {
                println!("Enter the income amount:");
                let mut amount = String::new();
                io::stdin().read_line(&mut amount).expect("Failed to read line");
                let amount: f64 = match amount.trim().parse() {
                    Ok(num) => num,
                    Err(_) => continue,
                };
                budget_manager.add_income(amount);
            }
            2 => {
                println!("Enter the expense amount:");
                let mut amount = String::new();
                io::stdin().read_line(&mut amount).expect("Failed to read line");
                let amount: f64 = match amount.trim().parse() {
                    Ok(num) => num,
                    Err(_) => continue,
                };
                budget_manager.add_expense(amount);
            }
            3 => {
                budget_manager.view_budget();
            }
            4 => {
                println!("Exiting the budget manager.");
                break;
            }
            _ => {
                println!("Invalid choice. Please enter a number between 1 and 4.");
            }
        }
    }
}

Step 4: Run the Application

cargo run

Follow the on-screen instructions to add income, expenses, and view your budget.

Feel free to enhance and customize the applications based on your learning goals and preferences. This is a basic example to get you started with Rust programming. If you have any questions or want to share your thoughts, please feel free to leave a comment or reach out to me. Let's continue to explore the vast possibilities of Rust together.

☞ Follow me on Twitter & Linkedin

☞ Kindly subscribe for my upcoming articles