Weekly Rust Trivia is a problem-oriented series of articles that assist developers while learning Rust. Every article solves simple, everyday development tasks using the Rust standard library or leveraging popular and proven crates.

Question: How to implement a generic stack in Rust?

To implement a generic stack, we can simply create a custom struct wrapping a vector (Vec<T>):

struct Stack<T> {
    items: Vec<T>,
}

impl<T> Stack<T> {
    fn new() -> Stack<T> {
        Stack { items: Vec::new() }
    }

    fn push(&mut self, item: T) {
        self.items.push(item);
    }

    fn pop(&mut self) -> Option<T> {
        self.items.pop()
    }

    fn is_empty(&self) -> bool {
        self.items.is_empty()
    }

    fn size(&self) -> usize {
        self.items.len()
    }
}

The implementation (impl<T> Stack<T>) uses a generic type T to allow it to store any type of data. The Stack struct has four methods: new, push, pop, is_empty, and size:

  • The new method creates a new instance of the Stack struct by creating a new empty vector (Vec<T>)
  • The push method adds a new item to the top of the stack by pushing it onto the vector
  • The pop method removes and returns the top item from the stack, or returns None if the stack is empty
  • The is_empty method returns a boolean value indicating whether or not the stack is empty
  • The size method returns the number of items currently in the stack

This implementation provides a basic functionality for a stack, which can be used to store and manipulate data in a Last-In-First-Out (LIFO) manner. The following code demonstrate using the generic stack with values of type i32:

fn main() {
    let mut stack = Stack::new();

    println!("Pushing 1");
    stack.push(1);
    println!("Pushing 2");
    stack.push(2);
    println!("Pushing 3");
    stack.push(3);

    println!("Size of the Stack: {}", stack.size());

    let first = stack.pop();
    println!("Got: {:?}", first);

    let second = stack.pop();
    println!("Got: {:?}", second);
    
    println!("Pushing 4");
    stack.push(4);
    
    let third = stack.pop();
    println!("Got: {:?}", third);
    
    let fourth = stack.pop();
    println!("Got: {:?}", fourth);
    
    let fifth = stack.pop();
    println!("Got: {:?}", fifth);
    
    println!("Is the stack empty? {}", stack.is_empty());
}

When we execute the program, the following output will be generated:

Pushing 1
Pushing 2
Pushing 3
Size of the Stack: 3
Got: Some(3)
Got: Some(2)
Pushing 4
Got: Some(4)
Got: Some(1)
Got: None
Is the stack empty? true