Vecs

vec stands for Vector. The basic details of a vec are:

  • They hold a collection of values (like an array)
  • All the values they hold must the same type (e.g. String)
  • It's possible to add and remove items from the vec

Creating a vec can be done with with vec![]. For example:

let alfa = vec![
  String::from("apple"),
  String::from("berry"),
  String::from("cherry")
];

Reading values in a vec can be done with using the zero based index/offest of the item to retrieve.

let bravo = &alfa[2]

The & in &alfa[2] means that we get a reference to the value so that ownership isn't transferred.

Full example:

fn main() {
  let alfa = vec![
    String::from("apple"),
    String::from("berry"),
    String::from("cherry")
  ];

  let bravo = &alfa[2];
  println!("bravo is {bravo}");
}

If the vec is mutable, adding more elements can be done with .push() like this:

alfa.push(String::from("date");
fn main() {
  let mut alfa = vec![
    String::from("apple"),
    String::from("berry"),
    String::from("cherry")
  ];

  alfa.push(String::from("date"));

  let bravo = &alfa[3];
  println!("bravo is {bravo}");
}

TODO: Cover .get() which returns an Option<&T> once your figure out how those work.

This is the example from The Rust Book

#![allow(unused)]
fn main() {
let alfa = vec![
  String::from("apple"),
  String::from("berry"),
  String::from("cherry")
];

let bravo = alfa.get(2);

match bravo {
  Some(bravo) => {
    println!("bravo is {}", bravo);
  }
  None => {
    println!("No value at index 2");
  }
}
}

Here's the same thing but using .get() to request index 3 which doesn't exist. The program doesn't crash. It shows the None arm of the match statement.

#![allow(unused)]
fn main() {
let alfa = vec![
  String::from("apple"),
  String::from("berry"),
  String::from("cherry")
];

let bravo = alfa.get(100);

match bravo {
  Some(bravo) => {
    println!("bravo is {}", bravo);
  }
  None => {
    println!("No value at index 100");
  }
}
}

This is an example of the panic/crash if you try to call an index that doesn't exist with the &alfa[] format.

#![allow(unused)]
fn main() {
let alfa = vec![
  String::from("apple"),
  String::from("berry"),
  String::from("cherry")
];

let bravo = &alfa[100];
}

Note that when you use the &alfa[2] format to get a value the program will panic and crash if the index is higher than the number of items availabe.

Maybe that means you should use get but only put it in after you talk about Option<&T>?

Or, maybe you leave this hear and address it later.


Like variables, having a mutable refernce to a vec means trying to add an immutable one won't be allowed. For example, pulling out one value via a reference then trying to update the vec by adding a new number

#![allow(unused)]
fn main() {
let mut alfa = vec![
  String::from("apple"),
  String::from("berry"),
  String::from("cherry")
];

let bravo = &alfa[2];

alfa.push(
  String::from("date")
);

println!("bravo is {bravo}");
}

The same scoping behavior that applies to variables applies to vecs. If the last time bravo is used is before the .push() to alfa everything will work because bravo goes out of scope which means the reference disappears.

#![allow(unused)]
fn main() {
let mut alfa = vec![
  String::from("apple"),
  String::from("berry"),
  String::from("cherry")
];

let bravo = &alfa[2];
println!("bravo is {bravo}");

alfa.push(
  String::from("date")
);
}

Iterating over a vector:

#![allow(unused)]
fn main() {
let alfa = vec![
  String::from("apple"),
  String::from("berry"),
  String::from("cherry")
];

for bravo in &alfa {
  println!("bravo is {bravo}");
}
}

Mutable version

#![allow(unused)]
fn main() {
let mut alfa = vec![
  String::from("apple"),
  String::from("berry"),
  String::from("cherry")
];

for bravo in &mut alfa {
  bravo.push_str("pie")
}

for charlie in alfa {
  println!("charlie is {charlie}")
}
}

TODO: Check in the *i += 50 derefernce format on the "Stroing Lists of Values with Vectors" page


Using Enums to hold multiple types.

#![allow(unused)]
fn main() {
enum Holder {
  Widget(String),
  Thing(String)
}

let holders = vec![
  Holder::Widget(String::from("alfa")),
  Holder::Thing(String::from("bravo"))
];

for item in &holders {
  match item {
    Holder::Widget(value) => {
      println!("got widget with {value}");
    }
    Holder::Thing(value) => {
      println!("got thing with {value}");
    }
  }
}
}