Clean Code in Rust: Principles and Examples for Beginners

Online Python Trainer for Beginners

Learn Python easily without overwhelming theory. Solve practical tasks with automatic checking, get hints in Russian, and write code directly in your browser — no installation required.

Start Course

Clean Code in Rust: Principles and Examples for Beginners

Rust is a powerful systems programming language renowned for its performance and memory safety. However, as in any other language, writing clean code is a critically important skill. Clean code is easier to read, maintain, and extend. For beginner Rust developers, mastering Clean Code principles from the start will help avoid common mistakes and make your code elegant and reliable. In this article, we will break down the basic principles of clean code in Rust with concrete examples.



1. Naming Variables and Functions

A good name should explain the programmer's intent. In Rust, it is customary to use snake_case for variables, functions, and modules, and CamelCase for types and traits.



Bad Example:

fn c(a: i32, b: i32) -> i32 {    let x = a + b;    x}


Good Example:

fn calculate_sum(first_number: i32, second_number: i32) -> i32 {    let result = first_number + second_number;    result}

Use meaningful names: user_name instead of un, process_data instead of pd. Avoid abbreviations unless they are universally accepted (e.g., idx for index).



2. Small Functions and Single Responsibility

The Single Responsibility Principle states: each function should do only one thing. If a function performs multiple actions, it is difficult to test and modify.



Bad Example (function does too much):

fn process_user(user_id: u32) {    // Getting user from DB    // Data validation    // Sending email    // Logging    println!("Processing user {}", user_id);}


Good Example (split into small functions):

fn get_user(user_id: u32) -> User {    // Logic for getting user    User { id: user_id }}

fn validate_user(user: &User) -> bool { // Validation logic user.id > 0}

fn send_email(user: &User) { // Email sending logic println!("Email sent to user {}", user.id);}

fn process_user(user_id: u32) { let user = get_user(user_id); if validate_user(&user) { send_email(&user); }}

Try to keep functions within 10-20 lines. If it is longer, break it down.



3. Error Handling: Use Result and Option

Rust encourages explicit error handling through the Result<T, E> and Option<T> types. Avoid using .unwrap() or .expect() in production code — this leads to a panic on error.



Bad Example (dangerous extraction):

fn read_file(path: &str) -> String {    let content = std::fs::read_to_string(path).unwrap(); // Can panic!    content}


Good Example (error handling):

use std::fs;

fn read_file(path: &str) -> Result<String, std::io::Error> { let content = fs::read_to_string(path)?; // The ? operator for propagating errors Ok(content)}

fn main() { match read_file("data.txt") { Ok(data) => println!("File content: {}", data), Err(e) => eprintln!("Error reading file: {}", e), }}

Use the ? operator for brevity, but always handle errors at the top level. For custom errors, create enums with the std::error::Error trait.



4. Comments and Documentation

Clean code should be self-documenting. Comments explain why, not what. For documenting public APIs, use /// (doc comments).



Bad Example (useless comment):

// Increment counter by 1counter += 1;

                
                

Blogs

Book Recommendations