Rust Quick Start

Overview

This chapter introduces you to Rust's basic syntax and core concepts through actual code examples. We'll start from Hello World and gradually build more complex programs.

🚀 Hello World

First Program

// src/main.rs
fn main() {
    println!("Hello, World!");
    println!("Hello, Rust!");

    // Formatted output
    let name = "Rust";
    let year = 2023;
    println!("Welcome to {} world! It's {} year.", name, year);
}
# Run program
cargo run
# Output:
# Hello, World!
# Hello, Rust!
# Welcome to Rust world! It's 2023 year.

Variables and Constants

fn main() {
    // Immutable variable (default)
    let x = 5;
    println!("Value of x is: {}", x);

    // x = 6; // Compile error! Immutable variables cannot be reassigned

    // Mutable variable
    let mut y = 5;
    println!("Value of y is: {}", y);
    y = 6; // Can modify
    println!("Now value of y is: {}", y);

    // Variable shadowing
    let x = x + 1; // Create new variable, shadow previous x
    println!("Shadowed value of x is: {}", x);

    // Constant
    const MAX_POINTS: u32 = 100_000;
    println!("Max score: {}", MAX_POINTS);
}

📊 Basic Data Types

Numeric Types

fn number_types() {
    // Integer types
    let small: i8 = -128;
    let big: i64 = 1_000_000;
    let unsigned: u32 = 42;

    // Floating point types
    let pi: f64 = 3.14159;
    let e: f32 = 2.71828;

    // Type inference
    let guess = 42; // Default i32
    let float_guess = 3.14; // Default f64

    println!("Integers: {}, {}, {}", small, big, unsigned);
    println!("Floats: {}, {}", pi, e);
    println!("Inferred: {}, {}", guess, float_guess);
}

Boolean and Character Types

fn bool_and_char() {
    // Boolean type
    let is_rust_awesome = true;
    let is_difficult: bool = false;

    // Character type (Unicode)
    let letter = 'A';
    let emoji = '😀';
    let chinese = '中';

    println!("Boolean values: {}, {}", is_rust_awesome, is_difficult);
    println!("Characters: {}, {}, {}", letter, emoji, chinese);
}

Compound Types

fn compound_types() {
    // Tuple
    let tuple: (i32, f64, char) = (42, 3.14, 'R');
    let (x, y, z) = tuple; // Destructuring
    println!("Tuple: {}, {}, {}", x, y, z);
    println!("Access tuple: {}", tuple.0);

    // Array
    let array = [1, 2, 3, 4, 5];
    let months = ["January", "February", "March"];
    let zeros = [0; 5]; // [0, 0, 0, 0, 0]

    println!("Array: {:?}", array);
    println!("First month: {}", months[0]);
    println!("All zeros array: {:?}", zeros);
}

🔧 Function Basics

Function Definition and Calling

fn main() {
    println!("Main function started");

    // Call functions
    greet();
    let result = add(5, 3);
    println!("5 + 3 = {}", result);

    // Functions with return values
    let (sum, product) = calculate(4, 6);
    println!("4 + 6 = {}, 4 * 6 = {}", sum, product);
}

// No parameters, no return value
fn greet() {
    println!("Hello, greetings from function!");
}

// Has parameters and return value
fn add(a: i32, b: i32) -> i32 {
    a + b // Expression, no semicolon
}

// Multiple return values (using tuple)
fn calculate(x: i32, y: i32) -> (i32, i32) {
    (x + y, x * y)
}

// Function with statements
fn verbose_add(a: i32, b: i32) -> i32 {
    println!("Calculating {} + {}", a, b);
    let result = a + b; // Statement
    result // Expression
}

🎛️ Control Flow

Conditional Statements

fn conditionals() {
    let number = 6;

    // if expression
    if number % 4 == 0 {
        println!("{} is divisible by 4", number);
    } else if number % 3 == 0 {
        println!("{} is divisible by 3", number);
    } else if number % 2 == 0 {
        println!("{} is divisible by 2", number);
    } else {
        println!("{} is not divisible by 2, 3, 4", number);
    }

    // if expression assignment
    let condition = true;
    let result = if condition { 5 } else { 6 };
    println!("Result is: {}", result);

    // Complex conditions
    let age = 18;
    let has_license = true;

    if age >= 18 && has_license {
        println!("Can drive");
    } else {
        println!("Cannot drive");
    }
}

Loops

fn loops() {
    // loop infinite loop
    let mut counter = 0;
    loop {
        counter += 1;
        if counter == 3 {
            println!("Skip 3");
            continue;
        }
        if counter == 6 {
            println!("End loop");
            break;
        }
        println!("Counter: {}", counter);
    }

    // while conditional loop
    let mut number = 3;
    while number != 0 {
        println!("Countdown: {}", number);
        number -= 1;
    }
    println!("Launch!");

    // for iteration loop
    let array = [10, 20, 30, 40, 50];
    for element in array.iter() {
        println!("Value is: {}", element);
    }

    // Range loop
    for number in 1..4 {
        println!("Number: {}", number);
    }

    // Loop with index
    for (index, value) in array.iter().enumerate() {
        println!("Value at index {} is {}", index, value);
    }
}

📦 Ownership Introduction

Basic Ownership

fn ownership_basics() {
    // Ownership transfer
    let s1 = String::from("hello");
    let s2 = s1; // s1's ownership transfers to s2

    // println!("{}", s1); // Compile error! s1 is no longer valid
    println!("{}", s2); // Normal

    // Cloning
    let s3 = String::from("world");
    let s4 = s3.clone(); // Deep copy
    println!("s3: {}, s4: {}", s3, s4); // Both valid

    // Copy for basic types
    let x = 5;
    let y = x; // Copy trait, both valid
    println!("x: {}, y: {}", x, y);
}

fn ownership_functions() {
    let s = String::from("hello");
    takes_ownership(s); // s's value moves into function
    // println!("{}", s); // Compile error! s is no longer valid

    let x = 5;
    makes_copy(x); // i32 is Copy, so x is still valid
    println!("{}", x); // Normal

    let s1 = gives_ownership(); // Function return value moves to s1
    println!("{}", s1);

    let s2 = String::from("world");
    let s3 = takes_and_gives_back(s2); // s2 moves into function, return value moves to s3
    println!("{}", s3);
}

fn takes_ownership(some_string: String) {
    println!("{}", some_string);
} // some_string goes out of scope and is dropped

fn makes_copy(some_integer: i32) {
    println!("{}", some_integer);
} // some_integer goes out of scope, nothing special happens

fn gives_ownership() -> String {
    let some_string = String::from("hello");
    some_string // Return, ownership moves to calling function
}

fn takes_and_gives_back(a_string: String) -> String {
    a_string // Return, ownership moves to calling function
}

References and Borrowing

fn references_and_borrowing() {
    let s1 = String::from("hello");

    // Immutable reference
    let len = calculate_length(&s1);
    println!("Length of '{}' is {}", s1, len); // s1 is still valid

    // Mutable reference
    let mut s2 = String::from("hello");
    change(&mut s2);
    println!("After modification: {}", s2);

    // Multiple immutable references
    let r1 = &s1;
    let r2 = &s1;
    println!("{} and {}", r1, r2); // Normal

    // Mutable reference restrictions
    let mut s3 = String::from("hello");
    let r3 = &mut s3;
    // let r4 = &mut s3; // Compile error! Only one mutable reference allowed at a time
    println!("{}", r3);
}

fn calculate_length(s: &String) -> usize {
    s.len()
} // s goes out of scope, but since it doesn't own the referenced value, nothing happens

fn change(some_string: &mut String) {
    some_string.push_str(", world");
}

🏗️ Struct Introduction

Defining and Using Structs

// Define struct
#[derive(Debug)] // Allow formatting with {:?}
struct User {
    username: String,
    email: String,
    sign_in_count: u64,
    active: bool,
}

// Tuple struct
#[derive(Debug)]
struct Point(i32, i32, i32);

fn struct_examples() {
    // Create struct instance
    let user1 = User {
        email: String::from("user@example.com"),
        username: String::from("someuser"),
        active: true,
        sign_in_count: 1,
    };

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

    // Mutable struct
    let mut user2 = User {
        email: String::from("another@example.com"),
        username: String::from("anotherusername"),
        active: true,
        sign_in_count: 1,
    };

    user2.email = String::from("newemail@example.com");
    println!("Updated email: {}", user2.email);

    // Struct update syntax
    let user3 = User {
        email: String::from("third@example.com"),
        username: String::from("thirduser"),
        ..user1 // Rest of fields same as user1
    };

    println!("User3: {:?}", user3);

    // Tuple struct
    let point = Point(1, 2, 3);
    println!("Point: {:?}", point);
    println!("x coordinate: {}", point.0);
}

// Associated functions and methods
impl User {
    // Associated function (similar to static method)
    fn new(email: String, username: String) -> User {
        User {
            email,
            username,
            active: true,
            sign_in_count: 1,
        }
    }

    // Method
    fn is_active(&self) -> bool {
        self.active
    }

    fn deactivate(&mut self) {
        self.active = false;
    }

    fn activate(&mut self) {
        self.active = true;
        self.sign_in_count += 1;
    }
}

fn struct_methods() {
    // Use associated function
    let mut user = User::new(
        String::from("test@example.com"),
        String::from("testuser")
    );

    println!("User active status: {}", user.is_active());

    user.deactivate();
    println!("Status after deactivation: {}", user.is_active());

    user.activate();
    println!("Status after activation: {}, login count: {}", user.is_active(), user.sign_in_count);
}

🎯 Enums and Matching

Enum Definition

#[derive(Debug)]
enum IpAddrKind {
    V4,
    V6,
}

#[derive(Debug)]
enum IpAddr {
    V4(u8, u8, u8, u8),
    V6(String),
}

#[derive(Debug)]
enum Message {
    Quit,
    Move { x: i32, y: i32 },
    Write(String),
    ChangeColor(i32, i32, i32),
}

fn enum_examples() {
    // Basic enum
    let four = IpAddrKind::V4;
    let six = IpAddrKind::V6;

    println!("IP versions: {:?}, {:?}", four, six);

    // Enum with data
    let home = IpAddr::V4(127, 0, 0, 1);
    let loopback = IpAddr::V6(String::from("::1"));

    println!("IP addresses: {:?}, {:?}", home, loopback);

    // Complex enum
    let messages = vec![
        Message::Quit,
        Message::Move { x: 10, y: 20 },
        Message::Write(String::from("Hello")),
        Message::ChangeColor(255, 0, 0),
    ];

    for msg in messages {
        process_message(msg);
    }
}

fn process_message(msg: Message) {
    match msg {
        Message::Quit => println!("Quit program"),
        Message::Move { x, y } => println!("Move to coordinates ({}, {})", x, y),
        Message::Write(text) => println!("Write text: {}", text),
        Message::ChangeColor(r, g, b) => println!("Change color to RGB({}, {}, {})", r, g, b),
    }
}

Option and Result

fn option_examples() {
    // Option enum
    let some_number = Some(5);
    let some_string = Some("string");
    let absent_number: Option<i32> = None;

    println!("Has value: {:?}, {:?}", some_number, some_string);
    println!("No value: {:?}", absent_number);

    // Handle Option
    match some_number {
        Some(value) => println!("Found value: {}", value),
        None => println!("No value"),
    }

    // Simplified matching with if let
    if let Some(value) = some_number {
        println!("if let found value: {}", value);
    }

    // unwrap_or provides default value
    let default_value = absent_number.unwrap_or(0);
    println!("Default value: {}", default_value);
}

fn result_examples() {
    // Result used for error handling
    let good_result: Result<i32, &str> = Ok(10);
    let bad_result: Result<i32, &str> = Err("Error occurred");

    match good_result {
        Ok(value) => println!("Success: {}", value),
        Err(error) => println!("Error: {}", error),
    }

    match bad_result {
        Ok(value) => println!("Success: {}", value),
        Err(error) => println!("Error: {}", error),
    }

    // Chained operations
    let result = divide(10, 2)
        .and_then(|x| divide(x, 2))
        .and_then(|x| divide(x, 0)); // This will error here

    match result {
        Ok(value) => println!("Final result: {}", value),
        Err(error) => println!("Calculation error: {}", error),
    }
}

fn divide(dividend: i32, divisor: i32) -> Result<i32, String> {
    if divisor == 0 {
        Err("Cannot divide by zero".to_string())
    } else {
        Ok(dividend / divisor)
    }
}

🎬 Complete Example: Guessing Game

use std::io;
use std::cmp::Ordering;
use rand::Rng;

fn guessing_game() {
    println!("Guess the number game!");

    let secret_number = rand::thread_rng().gen_range(1..101);

    loop {
        println!("Please enter your guess (1-100):");

        let mut guess = String::new();

        io::stdin()
            .read_line(&mut guess)
            .expect("Failed to read input");

        let guess: u32 = match guess.trim().parse() {
            Ok(num) => num,
            Err(_) => {
                println!("Please enter a valid number!");
                continue;
            }
        };

        println!("Your guess is: {}", guess);

        match guess.cmp(&secret_number) {
            Ordering::Less => println!("Too small!"),
            Ordering::Greater => println!("Too big!"),
            Ordering::Equal => {
                println!("Congratulations, you guessed correctly!");
                break;
            }
        }
    }
}

fn main() {
    // Run all examples
    println!("=== Data Type Examples ===");
    number_types();
    bool_and_char();
    compound_types();

    println!("\n=== Condition and Loop Examples ===");
    conditionals();
    loops();

    println!("\n=== Ownership Examples ===");
    ownership_basics();
    ownership_functions();
    references_and_borrowing();

    println!("\n=== Struct Examples ===");
    struct_examples();
    struct_methods();

    println!("\n=== Enum Examples ===");
    enum_examples();
    option_examples();
    result_examples();

    println!("\n=== Guessing Game ===");
    guessing_game();
}

📝 Chapter Summary

By studying this chapter, you should have mastered:

Rust Basics

  • ✅ Variables, constants, and basic data types
  • ✅ Function definition and calling
  • ✅ Control flow (conditionals and loops)
  • ✅ Basic concepts of ownership, borrowing, and references

Core Features

  • ✅ Defining and using structs
  • ✅ Enums and pattern matching
  • ✅ Option and Result types
  • ✅ Basic error handling

Practical Experience

  • ✅ Complete project example
  • ✅ Common programming patterns
  • ✅ Rust-specific programming mindset

Continue Learning: Next Chapter - Rust Basic Syntax