Learning Rust VecDeque – Step by Step

A word I heard as “deck” became a hands-on Rust lesson. Using Zed and Cargo on Debian, I practiced adding and removing cards at both ends of a VecDeque, corrected an editor-versus-terminal mix-up, and compared the code with Python’s deque.

I started this lesson with a word I had heard spoken: “deck.” In a Rust discussion, that likely meant deque, pronounced “deck,” short for double-ended queue.

A deque is a collection where items can be added or removed at either end. To understand it, I created a small Rust project on Debian, edited it in Zed, and ran several experiments using card names. By the final run, I had removed a card from each end and left only Ace.

Lab Journal

Creating the project

In my terminal, I ran:

cargo new ~/rust-deque-practice

Cargo created a Rust application project. The main files and folders were:

ItemPurpose
Cargo.tomlProject settings and dependencies
src/main.rsThe Rust source code I edited
Cargo.lockRecords resolved dependency versions
target/Build output created by Cargo

I opened the project in Zed:

zed ~/rust-deque-practice

Inside src/main.rs, I replaced the starter “Hello, world!” program with:

use std::collections::VecDeque;

fn main() {
    let mut cards = VecDeque::new();

    cards.push_back("Ace");
    cards.push_back("King");
    cards.push_front("Queen");

    println!("{cards:?}");
}

After saving with Ctrl+S, I ran these commands in the terminal:

cd ~/rust-deque-practice
cargo run

Cargo compiled and ran the program. The output was:

["Queen", "Ace", "King"]

Ace and King went to the back. Queen went to the front, which explains why Queen appeared first even though it was added last.

The editor and terminal mix-up

At one point, I pasted cd ~/rust-deque-practice and cargo run into the bottom of main.rs. Those are shell commands, so they did not belong in the Rust program.

The fix was to delete those two lines, save the file, and switch back to the terminal showing my (base) lvydvy@Debian:...$ prompt.

My working routine became: edit in Zed, save with Ctrl+S, then run cargo run in the terminal.

Trying both ends

I added removal operations immediately before println! and checked the output each time.

ExperimentRemoval codeObserved output
Keep all three cardsNo removal["Queen", "Ace", "King"]
Remove from the frontcards.pop_front();["Ace", "King"]
Remove from the backcards.pop_back();["Queen", "Ace"]
Remove from both endsFront removal, then back removal["Ace"]

Each run started the program again and created a fresh deque. The previous run’s removals did not carry over.

The Final Rust Program

use std::collections::VecDeque;

fn main() {
    let mut cards = VecDeque::new();

    cards.push_back("Ace");
    cards.push_back("King");
    cards.push_front("Queen");

    cards.pop_front();
    cards.pop_back();

    println!("{cards:?}");
}

The final output was:

["Ace"]

Reading the Rust Code Line by Line

use std::collections::VecDeque;

This brings the name VecDeque into scope from Rust’s standard library. std means the standard library, and collections contains collection types. No extra package installation was needed.

fn main() {

fn declares a function. main is the entry point for this application. The parentheses contain no parameters, and the braces enclose the function’s body.

let mut cards = VecDeque::new();

let introduces a variable named cards. mut allows us to change the deque through that variable. VecDeque::new() creates an empty deque, and = assigns it to cards.

Rust infers the element type from the card names added later. These quoted literals are string slices, so this collection has the type VecDeque<&str>. We did not need to write that type explicitly.

cards.push_back("Ace");

The dot calls a method on cards. This adds Ace to the back. The deque now contains ["Ace"].

cards.push_back("King");

This adds King after Ace, producing ["Ace", "King"].

cards.push_front("Queen");

This adds Queen before Ace, producing ["Queen", "Ace", "King"].

cards.pop_front();

This removes Queen from the front. Ace and King remain.

cards.pop_back();

This removes King from the back. Only Ace remains.

The removal methods also return the removed item wrapped in Some(...), or None if the deque is empty. In this lesson, we discard those return values and print the remaining collection. See the Rust VecDeque documentation.

println!("{cards:?}");

This displays the remaining cards and ends the output with a newline. The ! identifies println! as a macro. Inside the format string, cards names the variable and :? requests debug formatting, which makes the collection readable as ["Ace"].

The final } closes the main function. Blank lines separate the stages for readability. Semicolons terminate the statements used here.

How This Compares with Python

Python provides the same kind of collection as collections.deque. This equivalent example is included for comparison; the terminal runs in this lesson were Rust runs.

from collections import deque

cards = deque()

cards.append("Ace")
cards.append("King")
cards.appendleft("Queen")

cards.popleft()
cards.pop()

print(list(cards))

Expected output:

['Ace']

list(cards) makes a list for display, so the output resembles the Rust example. Printing cards directly would show deque(['Ace']).

Matching the operations

ActionRust VecDequePython deque
Create an empty dequeVecDeque::new()deque()
Add at the frontpush_front("Queen")appendleft("Queen")
Add at the backpush_back("Ace")append("Ace")
Remove at the frontpop_front()popleft()
Remove at the backpop_back()pop()

Python’s removal methods return the item directly. Removing from an empty deque raises IndexError, while Rust’s methods return None. These behaviors are documented in the Python deque reference and the Rust VecDeque reference.

Differences I can recognize already

TopicRust in this lessonPython equivalent
Changing the collectionRequires mut on this bindingNo mut keyword needed
Element typesOne element type, checked during compilationCan contain objects of different types
Program structureCode is inside fn main()This script can run at the top level
BlocksBraces mark the function bodyIndentation marks blocks when needed
Runningcargo run builds as needed, then runsA saved script can run with python3 filename.py

Python’s familiar syntax makes the idea easier to recognize. Rust asks me to be more explicit about mutation and checks types before the program runs. The operations on the cards remain the same.

A Python list can also add and remove items, but collections.deque is the closer match for this exercise. It supports efficient operations at both ends; removing the first item of a list with pop(0) shifts the remaining elements. See the Python collections documentation.

Lessons Learned

  • “Deque” sounds like “deck” and means double-ended queue.
  • push adds an item; pop removes one.
  • Front and back are positions in the collection, not alphabetical order.
  • Saving in Zed and running in the terminal are separate steps.
  • Each new program run rebuilds the example’s collection from scratch.
  • Changing one operation at a time makes the output easier to explain.

The final ["Ace"] output showed that I had successfully added three items, removed one from each end, and understood why the middle item remained.