Vectors

Using Vec<T> for dynamic arrays.

Beginner⏱️ 30 min📚 Prerequisites: 1

Vectors

Vec<T> is a dynamic array that stores values of the same type.

Creating a Vector

RUST
let v: Vec<i32> = Vec::new();
let v = vec![1, 2, 3];  // Using macro

Adding Values

RUST
let mut v = Vec::new();
v.push(5);
v.push(6);
v.push(7);

Accessing Values

RUST
let v = vec![1, 2, 3, 4, 5];

let third: &i32 = &v[2];  // Index - panics if out of bounds
let third: Option<&i32> = v.get(2);  // Safe - Option

Iteration

RUST
let v = vec![100, 32, 57];
for i in &v {
    println!("{}", i);
}

// Modifying during iteration
let mut v = vec![100, 32, 57];
for i in &mut v {
    *i += 50;
}

Using Enum to Store Different Types

RUST
enum SpreadsheetCell {
    Int(i32),
    Float(f64),
    Text(String),
}

let row = vec![
    SpreadsheetCell::Int(3),
    SpreadsheetCell::Text(String::from("blue")),
    SpreadsheetCell::Float(10.12),
];

Code Examples

Basic Vector

Creating and using a vector

RUST
fn main() {
    let mut v = Vec::new();
    v.push(1);
    v.push(2);
    v.push(3);
    println!("Vector: {:?}", v);
    let v2 = vec![4, 5, 6];
    println!("Vector2: {:?}", v2);
}

Explanation:

Vec::new() creates an empty vector. The vec![] macro creates a vector with initial values. The push() method adds elements.

Accessing Values

Accessing vector elements

RUST
fn main() {
    let v = vec![1, 2, 3, 4, 5];
    let third = &v[2];
    println!("Third element: {}", third);
    match v.get(2) {
        Some(third) => println!("Third element: {}", third),
        None => println!("No third element"),
    }
    match v.get(100) {
        Some(value) => println!("Value: {}", value),
        None => println!("No 100th element"),
    }
}

Explanation:

The v[index] syntax panics if the index is invalid. v.get(index) returns an Option, which is safer.

Iteration

Iterating through a vector

RUST
fn main() {
    let v = vec![100, 32, 57];
    for i in &v {
        println!("{}", i);
    }
    let mut v = vec![100, 32, 57];
    for i in &mut v {
        *i += 50;
    }
    println!("Modified vector: {:?}", v);
}

Explanation:

The for loop can be immutable (&v) or mutable (&mut v). In mutable iteration, you need to dereference the value with the * operator.

Blockchain: Transaction Vector

Using vectors to store blockchain transactions

RUST
struct Transaction {
    from: String,
    to: String,
    amount: u64,
}
fn main() {
    let mut transactions = Vec::new();
    transactions.push(Transaction {
        from: String::from("0xAlice"),
        to: String::from("0xBob"),
        amount: 100,
    });
    transactions.push(Transaction {
        from: String::from("0xBob"),
        to: String::from("0xCharlie"),
        amount: 50,
    });
    println!("Block contains {} transactions", transactions.len());
    for (index, tx) in transactions.iter().enumerate() {
        println!("Tx {}: {} -> {} ({} tokens)",
                index + 1, tx.from, tx.to, tx.amount);
    }
}

Explanation:

Blocks contain vectors of transactions. Vectors are perfect for this because blocks can have varying numbers of transactions. We can iterate through them to process each transaction.

Blockchain: Chain of Blocks

Using vectors to represent blockchain

RUST
struct Block {
    index: u64,
    hash: String,
}
struct Blockchain {
    blocks: Vec<Block>,
}
impl Blockchain {
    fn new() -> Self {
        Blockchain { blocks: Vec::new() }
    }
    fn add_block(&mut self, block: Block) {
        self.blocks.push(block);
    }
    fn height(&self) -> usize {
        self.blocks.len()
    }
    fn get_latest(&self) -> Option<&Block> {
        self.blocks.last()
    }
}
fn main() {
    let mut chain = Blockchain::new();
    chain.add_block(Block { index: 0, hash: String::from("genesis") });
    chain.add_block(Block { index: 1, hash: String::from("hash1") });
    chain.add_block(Block { index: 2, hash: String::from("hash2") });
    println!("Blockchain height: {}", chain.height());
    if let Some(latest) = chain.get_latest() {
        println!("Latest block: index {}, hash {}", latest.index, latest.hash);
    }
}

Explanation:

A blockchain is essentially a vector of blocks. Each block is added to the end, and we can access the latest block or iterate through all blocks. This is the foundation of blockchain data structures.

Exercises

Vector Operations

Create a vector, add elements, and print all elements!

Easy

Starter Code:

RUST
fn main() {
}

Blockchain: Transaction List

Create a vector of transaction amounts and calculate total!

Easy

Starter Code:

RUST
fn main() {
}