Skip to content

Vectors

Updated
17 Sept 2026
5 min read
2 sections
Page 16 of 18
Rust
rust
fn main() {
    let a = [1, 2, 3, 4, 5];
    let v: Vec<i32> = Vec::new();
}
  • vector can grow or shrink in size
rust
fn main() {
    let a = [1, 2, 3, 4, 5];
    let mut v: Vec<i32> = Vec::new();
    v.push(6);
    v.push(7);
    v.push(8);

    let v2 = vec![1, 2, 3, 4, 5];
}
  • vec! macro creates a new vector with initial values of the inffered type
rust
use std::vec;

fn main() {
    let a = [1, 2, 3, 4, 5];
    let mut v: Vec<i32> = Vec::new();
    v.push(6);
    v.push(7);
    v.push(8);
    {
        let v2 = vec![1, 2, 3, 4, 5];
    }
}
  • Refferecing elements in a vector
rust
fn main() {
        let v2 = vec![1, 2, 3, 4, 5];
        let third: &i32 = &v2[2];
        println!("The third element is {}", third);
}
rust
fn main () {
    let v2 = vec![1, 2, 3, 4, 5];
    let third: &i32 = &v2[20];
    println!("The third element is {}", third);
}
Runtime Error: thread main panicked at 'index out of bounds: the len is 5 but the index is 20'
  • vector are stored in the heap, so size of a vector is not known at compile time
  • array are stored on the stack, so size of an array is known at compile time
rust
fn main () {
    let v2 = vec![1, 2, 3, 4, 5];
    let elem: Option<&i32> = v2.get(2);

    match elem {
        Some(value) => println!("The element is {}", value),
        None => println!("There is no element"),
    }
}
  • get method returns Option<&T>, which is Some(&element) or None
rust
fn main() {
    let mut v = vec![1, 2, 3, 4, 5];

    let elem = &v[2];
    v.push(6);

    println!("The third element is {}", elem);
}
Error: cannot borrow v as mutable because it is also borrowed as immutable
  • when we use an immutable refference to a vector, we expect to get the orginal vector back, which means that the orginal vector has to be stored somewhere else in memory
  • which cannot be done because refferenced to the modified vector

Iterating over the values in a vector

rust
fn main() {
    let v = vec![1, 2, 3, 4, 5];
    for i in &v {
        println!("{}", i);
    }
}
  • &v{:rust} creates an immutable refference to the vector
rust
fn main() {
    let mut v = vec![1, 2, 3, 4, 5];
    for i in &mut v {
        *i += 50;
    }

    for i in &v {
        print!("{} ", i);
    }
}
  • &mut v{:rust} creates a mutable refference to the vector
  • *i{:rust} dereferences i{:rust} to get the value in the vector
Out · output
$ cargo run

51 52 53 54 55

Storing Enums in a Vector

rust
fn main() {
    enum SpreadsheetCell {
        Int(i32),
        Float(f64),
        Text(String),
    }

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

    match &row[0] {
        SpreadsheetCell::Int(value) => println!("The value is {}", value),
        _ => println!("Not an integer"),
    }
}

Strings

  • Strings are stored as a collection of UTF-8 encoded bytes
  • ASCII characters are encoded in 1 byte, while other characters are encoded in 2 bytes
  • Unicode scalar values are stored in 4 bytes
  • UTF-8 encoding allows for a string to be valid UTF-8, but not valid Unicode, size of a string is not known at compile time
rust
fn main() {
    let hello = String::from("السلام عليكم");
    let hello = String::from("Dobrý den");
    let hello = String::from("Hello");
    let hello = String::from("שלום");
    let hello = String::from("नमस्ते");
    let hello = String::from("こんにちは");
    let hello = String::from("안녕하세요");
    let hello = String::from("你好");
    let hello = String::from("Olá");
    let hello = String::from("Здравствуйте");
    let hello = String::from("Hola");
}

Appending to a String

rust
fn main() {
    let mut s = String::from("Hello");
    s.push_str(", World");
    s.push('!');
    println!("{}", s);
}
  • push_str appends a string slice to a string
  • push appends a single character to a string

Concatenation with the + Operator

rust
fn main() {
    let s1 = String::from("Hello");
    let s2 = String::from(", World");
    let s3 = s1 + &s2;
    println!("{}", s3);
}
  • + operator uses the add method, which takes ownership of s1 and borrows s2
  • fn add(self, s: &str) -> String{:rust}, takes in an refference to a string slice &str and returns a new string
  • s3 is the result of the concatenation, so it takes ownership of s1 and s1 is no longer valid

Formatting Strings

rust
fn main() {
    let s1 = String::from("tic");
    let s2 = String::from("tac");
    let s3 = String::from("toe");

    let s = format!("{}-{}-{}", s1, s2, s3);
    println!("{}", s);
}
  • format! macro creates a string without taking ownership of any of its parameters

Indexing into Strings

rust
fn main() {
    let s1 = String::from("hello");
    let h = s1[0];
}
| let h = s1[0];
| ------------^ string indices are ranges of usize
|
= help: the trait SliceIndex<str> is not implemented for {integer}, which is required by String: Index<_>
rust
use unicode_segmentation::UnicodeSegmentation;

fn main() {
    let s1 = String::from("नमस्ते");

    for b in s1.bytes() {
        print!("{} ", b);
    }

    for c in s1.chars() {
        print!("{} ", c);
    }

    for g in s1.graphemes(true) {
        print!("{} ", g);
    }
}
  • String is a wrapper over a Vec<u8>, so indexing into a string would return a byte, which is not a character

Bytes

  • bytes(){:rust} method returns an iterator over the bytes of a string

[224, 164, 168, 224, 164, 174, 224, 164, 184, 224, 165, 141, 224, 164, 164, 224, 165, 135]{:rust}

Scalar Values

  • chars(){:rust} method returns an iterator over the scalar values of a string

['न', 'म', 'स', '्', 'त', 'े']{:rust}

Grapheme Clusters

  • graphemes(){:rust} in 📦 unicode-segmentation crate method returns an iterator over the grapheme clusters of a string

["न", "म", "स्", "ते"]{:rust}

Using &str[0]{:rust} is not a good idea because it may not return the expected character

Hash Maps

  • A hash map stores a collection of key-value pairs
rust
use std::collections::HashMap;

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

    scores.insert(String::from("Blue"), 10);
    scores.insert(String::from("Yellow"), 50);

    let team_name = String::from("Blue");
    let score = scores.get(&team_name);

    match score {
        Some(value) => println!("The score is {}", value),
        None => println!("There is no score"),
    }
}
  • HashMap::new(){:rust} creates a new hash map
  • insert(){:rust} method inserts a key-value pair into the hash map
  • get(){:rust} method returns an Option<&V> where V is the value type
rust
use std::collections::HashMap;

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

    scores.insert(String::from("Blue"), 10);
    scores.insert(String::from("Blue"), 50);
    //The score is 50

    scores.entry(String::from("Yellow")).or_insert(10);
    scores.entry(String::from("Yellow")).or_insert(50);
    // The score is 10

}
  • entry(){:rust} method returns an Entry enum
  • insert(){:rust} method inserts a value, overwrites the existing value
  • or_insert(){:rust} method inserts a value if the key does not exist
rust
use std::collections::HashMap;
fn main() {
    let text = "hello world wonderful world";

    let mut map = HashMap::new();

    for word in text.split_whitespace() {
        let count = map.entry(word).or_insert(0);
        *count += 1;
    }

    println!("{:?}", map);
}
  • or_insert(){:rust} method returns a mutable reference to the value &mut V{:rust}
  • *count += 1{:rust} dereferences count to get the value in the hash map