Rust is a systems programming language that runs blazingly fast, prevents segfaults, and guarantees thread safety. As a beginner, practical code examples are crucial for grasping new concepts and building real-world applications. This comprehensive guide provides over 20 rust code examples for common programming tasks.

1. Hello World

The "Hello World" program is the simplest way to ensure Rust is installed and working properly:

fn main() {
    println!("Hello World!"); 
}

This program uses the println! macro to print a string to standard output. The main function is the entry point for execution.

2. Read User Input

Reading input from a user is done with the stdin() method of the io::stdin() function:

use std::io;

fn main() {
    let mut input = String::new();
    io::stdin()
        .read_line(&mut input)
        .expect("Failed to read line");

    println!("You entered: {}", input);
} 

This reads a single line into a mutable input string. The expect call handles errors.

3. Format Print Output

Rust provides various macros to format text output:

fn main() {
    let app_name = "Rust Blog";
    let downloads = 1_024;

    println!("Welcome to {}!", app_name);
    println!("Downloads: {}", downloads); 
    println!("Version: {:.1}", 1.2);
}

println! works like C‘s printf, formatting variables into the string. The :{.precision} specifies a floating point precision.

4. If Conditional

An if statement allows executing code selectively based on boolean conditions:

fn main() {
    let admin = true;

    if admin == true {
        println!("You have admin rights!");
    } else {
        println!("You do not have admin rights.");
    }
}

if statements support else if and else blocks. Variables must be explicitly compared against a boolean with == true or == false.

5. Match Conditional

A match statement works like a switch from other languages:

fn get_department(id: u32) -> &‘static str {
    match id {
        1 => "Engineering",
        2 => "Finance",
        3 => "Marketing",
        _ => "Unknown"
    }
}

fn main() {
    let department = get_department(3); 
    println!("Matched: {}", department);
}

The _ catch-all pattern handles non-matching cases.

6. While Loop

A while loop repeats code as long as a condition is true:

fn main() {
    let mut counter = 1;

    while counter < 11 {
        println!("Counter: {}", counter);

        counter += 1;
    }
}

The loop increments counter each iteration until the value reaches 10. mut allows modifying the variable.

7. For Range Loop

For loops iterate a specific number of times with a range:

fn main() {
    for i in 1..11 {
        println!("Number: {}", i); 
    }
}

This loops from 1 to 10, excluding the end number. The range could also count downwards with 10..=0.

8. Loop Over Collections

You can iterate reference elements from a vector with for:

fn main() {
    let names = vec!["Bob", "Anne", "Steve"];

    for name in &names {
        println!("Hello {}!", name);
    }
}

Looping over &names borrows references to the elements rather than moving them.

9. Loop and Modify Collection

To loop and modify a collection, make it mutable:

fn main() {
    let mut scores = [10, 20 , 30];

    for score in &mut scores {
        *score += 5;
    }

    println!("Scores: {:?}", scores);
}

Now *score dereferences each element for modification.

10. Handle Errors

Errors are handled via Result enums with pattern matching:

use std::num::ParseIntError;

fn main() -> Result<(), ParseIntError> {
    let number = "10a";
    let n: i8 = match number.trim().parse() {
        Ok(n) => n,
        Err(e) => return Err(e),
    };

    println!("Number: {}", n); 
    Ok(())
}

The ? operator is also used for concise error propagation.

11. Vector

A vector stores a growable list of elements:

fn main() {
    // Construct empty vector
    let mut values = Vec::new(); 

    // Add elements
    values.push(1);
    values.push(3);

    // Show elements 
    println!("Values: {:?}", values);
}

Vectors dynamically grow and shrink as elements are added and removed.

12. Vector Loop

Loop through vector values with a for loop:

fn main() {
    let mut values = vec![1, 2, 3];

    // Loop and modify 
    for value in &mut values { 
        *value += 1;
    }

    println!("Values: {:?}", values);
}

Borrowing vector elements immutably would prevent modifications.

13. Vector Sort

Sort a vector with the sort method:

fn main() {
    let mut values = vec![3, 1, 2];

    // Sort vector 
    values.sort();

    println!("Sorted: {:?}", values);
}

For custom sorting behavior, pass a closure comparator function to sort_by.

14. HashMap

A hash map stores key-value pairs:

use std::collections::HashMap;

fn main() {
    let mut players = HashMap::new();

    players.insert("Russell", 13); 
    players.insert("Wilt", 100);

    println!("{:?}", players); 
}

Map elements are automatically sorted by key. get and contains_key find values.

15. HashMap Loop

You can loop through key-value pairs in a map:

use std::collections::HashMap;

fn main() {
    let players = hashmap!{"Russell" => 13, "Wilt" => 100};

    for (name, number) in &players {
        println!("{} wore number {}", name, number);
    }
} 

Each iteration provides a tuple with both elements.

16. Modules

Code can be organized into modules:

// In file arithmetic.rs
pub fn add(a: i32, b: i32) -> i32 {
    a + b
}

// In main.rs
mod arithmetic;

fn main() {
    let sum = arithmetic::add(5, 2);
    println!("Sum: {}", sum);
}

The module file path matches the name, like arithmetic.rs. Declare public functions with pub.

17. Structs

Custom data structures are defined using struct:

struct Book {
    title: String,
    chapters: u8,
    author: String,
}

fn main() {
    let book = Book {
        title: String::from("Frankenstein"), 
        chapters: 24,
        author: String::from("Mary Shelley"),
    };

    println!("{} by {} has {} chapters", 
        book.title, book.author, book.chapters);
}

Struct fields are accessed using dot notation. The struct is instantiated like an object.

18. Impl Methods

Methods are added to structs with impl:

struct Circle {
    radius: f64
}

impl Circle {
    // Associated function 
    fn new(radius: f64) -> Self {
        Self { radius } 
    }

    // Instance method
    fn area(&self) -> f64 {
        std::f64::consts::PI * (self.radius * self.radius)
    }
}

fn main() {
    let c = Circle::new(5.0);
    println!("Area: {}", c.area());
}

Self refers to the struct type. Methods take a struct reference with &self.

19. Traits

Traits define shared behavior between types:

trait Summary {
    // Mandatory method
    fn summarize(&self) -> String;
}

struct Book {
    // ...
}

// Implement trait for type  
impl Summary for Book {
    fn summarize(&self) -> String {
        format!("{} by {}", self.title, self.author)
    }
}

fn main() {
    let book = Book { /* ... */ };
    println!("Summary: {}", book.summarize());
}

Traits are similar to interfaces in other languages. Types like Book can implement them.

20. Generic Structs

Structs can be made generic over one or more type parameters:

struct Point<T> {
    x: T,
    y: T,
}

fn main() {
    let p1 = Point{x: 5, y: 10}; 
    let p2 = Point{x: 5.5, y: 8.2};

    println!("P1 = ({}, {})", p1.x, p1.y); 
    println!("P2 = ({}, {})", p2.x, p2.y);
}

Now Point supports any data types, not just floats/integers.

21. Threads

Concurrency is achieved via threads and message passing:

use std::thread;

fn main() {
    // Spawn thread in the background
    thread::spawn(|| {
        println!("...printing from spawned thread");
    });

    // Main thread continues execution
    println!("...printing from main thread");
}

The closure passed to spawn executes concurrently in the new thread. Accessing data must be synchronized manually between threads.

22. Channels

The transmission of data between threads uses channels:

use std::sync::mpsc::channel;
use std::thread;

fn main() {
    let (tx, rx) = channel();

    for id in 0..5 {
        let tx = tx.clone();
        thread::spawn(move || {
            let msg = format!("Message {}", id);
            tx.send(msg).unwrap(); 
        });
    }

    for msg in rx {
        println!("Got {}", msg);
    }
}

The tx handle sends data. rx receives in the main thread. Channels manage safe simultaneous data transmission.

23. Read File

Reading a file loads the contents into memory:

use std::fs;
use std::io::Read;

fn main() -> Result<(), std::io::Error> {
    let mut text = String::new();

    // Open file
    let mut f = fs::File::open("notes.txt")?;  
    f.read_to_string(&mut text)?;

    println!("File contents:\n{}", text);

    Ok(())
}

The question mark operator passes errors up the call stack for handling.

24. Write File

To write text to a file:

use std::fs::File;
use std::io::{self, Write};

fn main() -> Result<(), io::Error> {
    let text = String::from("\nLorem Ipsum ..."); 

    let mut file = File::create("lorem.txt")?;
    file.write_all(text.as_bytes())?;

    Ok(())
}

The write_all method accepts a byte slice. Files are automatically flushed and closed at the end of scope.

Conclusion

Rust‘s design prevents entire classes of bugs while providing great performance. These 24 code samples demonstrate how to use Rust for common tasks like I/O, collections, threading, and more. With this solid base, you can start building real programs in Rust! Let me know if you have any other questions.

Similar Posts

Leave a Reply

Your email address will not be published. Required fields are marked *