Rust: Vetores em Rust (Vec)

Última atualização: 2026-08-26

Vec<T> (vector) é a matriz dinâmica mais utilizada na biblioteca padrão do Rust — ela pode aumentar ou diminuir em tempo de execução, e todos os dados são alocados no heap. É o equivalente, no Rust, a um “ArrayList” ou a uma “lista do Python”.

Se os arrays são como “armários de armazenamento de tamanho fixo”, então o Vec é como um “armazém escalável” — ele se expande automaticamente quando o espaço acaba, de modo que você não precisa gerenciar a memória manualmente.


1. O que você vai aprender


2. A história de uma caixa de supermercado

(1) Frustração: não saber o tamanho do carrinho de compras

Tom está desenvolvendo um sistema de caixa para supermercados. O carrinho de compras do cliente:

RUST
// The problem with arrays -- you must know how many items in advance!
let cart: [&str; 3] = ["milk", "bread", "eggs"];

// Customer says: "Add one more cola"
// Arrays can't grow dynamically -- you need to redeclare...
let mut cart2 = ["milk", "bread", "eggs", "cola"];
// Customer: "Remove eggs, add butter instead"
// Modify every time? This is painful!

O tamanho de um array é definido em tempo de compilação. Mas, no caso de um carrinho de compras, não se sabe se um cliente comprará 3 itens ou 30. É necessária uma estrutura de dados que aumente dinamicamente em tempo de execução.

(2) Solução para o Rust Vec

RUST
fn main() {
    // Start with an empty cart
    let mut cart: Vec<&str> = Vec::new();

    // Customer adds items one by one
    cart.push("milk");
    cart.push("bread");
    cart.push("eggs");
    println!("Cart has {} items: {:?}", cart.len(), cart);

    // Customer adds more
    cart.push("cola");
    println!("Added cola: {:?}", cart);

    // Customer removes an item
    cart.pop();
    println!("Removed last: {:?}", cart);

    // Check what's inside
    println!("Current cart: {:?}", cart);
}

Vec::new() Crie um array dinâmico vazio; push adicione elementos (o array se redimensiona automaticamente); pop remova o último elemento. Não é necessário especificar um tamanho — o Vec gerencia automaticamente a memória no heap.


3. Matriz dinâmica Vec

(1) Visão geral do conceito

100%
graph LR
    A[Vec&lt;T&gt; dynamic array] --> B[Creation]
    A --> C[CRUD operations]
    A --> D[Capacity management]
    A --> E[Conversion]

    B --> B1[Vec::new()]
    B --> B2[vec! macro]
    B --> B3[collect()]

    C --> C1[push / pop]
    C --> C2[insert / remove]
    C --> C3[index / .get()]

    D --> D1[capacity: allocated]
    D --> D2[len: actual use]
    D --> D3[shrink_to_fit]

    E --> E1[From array]
    E --> E2[Back to array]

(2) Comparando vetores e matrizes

Dimensão Matriz [T; N] Vetor Vec<T>
Tamanho Fixo na compilação Aumenta dinamicamente durante a execução
Local de alocação Pilha (normalmente) Heap
Redimensionamento Não compatível Redimensionamento automático para o dobro
Riqueza da API Limitada Extremamente rica
Velocidade de acesso Extremamente rápida (contígua na pilha) Extremamente rápida (contígua no heap)
Casos de uso Tamanho fixo, alocado na pilha Número desconhecido, adições e remoções frequentes
Sobrecarga de desempenho Nenhuma push pode acionar uma realocação

(3) Referência rápida aos métodos comuns do Vec

Método Tipo de retorno Descrição Complexidade temporal
push(val) () Inserir no final O(1) amortizado
pop() Option<T> Pop-up da cauda O(1)
insert(idx, val) () Inserir em uma posição especificada O(n)
remove(idx) T Remover em uma posição especificada O(n)
get(idx) Option<&T> Acesso seguro O(1)
len() usize Número de elementos O(1)
capacity() usize Capacidade alocada O(1)
clear() () Resolver em O(n)
contains(&val) bool Contém O(n)
sort() () Classificação no próprio espaço O(n log n)
dedup() () Remover duplicatas (é preciso ordenar primeiro) O(n)
retain(f) () Manter os elementos que atendem aos critérios O(n)
shrink_to_fit() () Liberar o excesso de capacidade

(4) Comparação dos métodos de iteração Vec

Método Sintaxe Propriedade Disponível em Vec
Iteração emprestada for x in &v Referência somente leitura Disponível
Percorrimento variádico for x in &mut v Referências variádicas Disponível (corrigido)
Percorrimento de consumo for x in v Transferência de propriedade Indisponível
Iterador v.iter() Referência somente leitura Disponível
Iteração de enumeração v.iter().enumerate() Referência somente leitura + Índice Disponível

4. Exemplo

▶ Exemplo 1: A macro vec! e push/pop (Dificuldade ⭐)

RUST
// ============================================
// Vec: vec! macro, push, pop, len, is_empty
// ============================================

fn main() {
    // Method 1: Vec::new()
    let mut v1: Vec<i32> = Vec::new();
    v1.push(10);
    v1.push(20);
    v1.push(30);
    println!("v1: {:?}, len={}", v1, v1.len());

    // Method 2: vec! macro (most common)
    let mut v2 = vec!["apple", "banana", "cherry"];
    println!("v2: {:?}, len={}", v2, v2.len());

    // Method 3: vec! with repeated value
    let v3 = vec![0; 5];
    println!("v3 (five zeros): {:?}", v3);

    // push: add to the end
    v2.push("date");
    println!("After push: {:?}", v2);

    // pop: remove from the end
    let last = v2.pop();
    println!("Popped: {:?}", last);
    println!("After pop: {:?}", v2);

    // is_empty
    println!("v2 empty? {}", v2.is_empty());

    // Access by index
    println!("v2[0] = {}", v2[0]);

    // len
    println!("v2 length: {}", v2.len());
}

Resultado:

TEXT 📖 Somente leitura
v1: [10, 20, 30], len=3
v2: ["apple", "banana", "cherry"], len=3
v3 (five zeros): [0, 0, 0, 0, 0]
After push: ["apple", "banana", "cherry", "date"]
Popped: Some("date")
After pop: ["apple", "banana", "cherry"]
v2 empty? false
v2[0] = apple
v2 length: 3

vec! é a maneira mais comum de criar uma lista — vec!["a", "b", "c"] ou vec![0; 5] (5 zeros). push acrescenta um elemento ao final; pop retira um elemento do final (retorna Option<T>). len() retorna o número de elementos da lista.


▶ Exemplo 2: Inserção/remoção e gerenciamento de capacidade (Dificuldade ⭐⭐)

RUST
// ============================================
// Vec: insert, remove, capacity vs length
// ============================================

fn main() {
    let mut cart: Vec<&str> = Vec::with_capacity(3);

    // capacity vs length
    println!("Initial -- len: {}, cap: {}", cart.len(), cart.capacity());

    cart.push("milk");
    cart.push("bread");
    cart.push("eggs");
    println!("After 3 pushes -- len: {}, cap: {}", cart.len(), cart.capacity());

    // insert at arbitrary position
    cart.insert(1, "cola");  // insert "cola" at index 1
    println!("After insert at 1: {:?}", cart);
    println!("Now -- len: {}, cap: {}", cart.len(), cart.capacity());
    // Capacity may have doubled!

    // remove at arbitrary position
    let removed = cart.remove(2);  // remove element at index 2
    println!("Removed: {}", removed);
    println!("After remove at 2: {:?}", cart);

    // get -- safe access (returns Option<&T>)
    match cart.get(0) {
        Some(item) => println!("First item: {}", item),
        None => println!("Empty cart!"),
    }

    // Try an out-of-bounds index with get (safe)
    match cart.get(99) {
        Some(item) => println!("Item at 99: {}", item),
        None => println!("Index 99 is out of bounds!"),
    }

    // shrink_to_fit: reduce capacity to match length
    cart.shrink_to_fit();
    println!("After shrink -- len: {}, cap: {}", cart.len(), cart.capacity());
}

Resultado:

TEXT 📖 Somente leitura
Initial -- len: 0, cap: 3
After 3 pushes -- len: 3, cap: 3
After insert at 1: ["milk", "cola", "bread", "eggs"]
Now -- len: 4, cap: 6
Removed: bread
After remove at 2: ["milk", "cola", "eggs"]
First item: milk
Index 99 is out of bounds!
After shrink -- len: 3, cap: 3

insert(idx, val) insere na posição especificada (deslocando os elementos subsequentes para a direita), remove(idx) remove o elemento na posição especificada e o retorna. capacity é a quantidade de memória alocada para Vec (que pode ser maior que len), e shrink_to_fit() libera o espaço excedente. .get() Garante um acesso seguro; em caso de acesso fora dos limites, retorna None em vez de causar um panic.


▶ Exemplo 3: Métodos de percorrimento e iteração de vetores (Dificuldade ⭐⭐)

RUST
// ============================================
// Vec: iteration, mutation, and functional methods
// ============================================

fn main() {
    let mut prices = vec![29.9, 49.9, 15.5, 99.0, 8.8];

    // Method 1: for-in by reference
    print!("Prices: ");
    for p in &prices {
        print!("{:.1} ", p);
    }
    println!();

    // Method 2: mutable iteration (add tax)
    for p in &mut prices {
        *p *= 1.1;  // 10% tax
    }
    println!("With 10% tax: {:?}", prices);

    // Method 3: .iter().enumerate()
    for (i, p) in prices.iter().enumerate() {
        println!("Item {}: {:.2}", i, p);
    }

    // Method 4: functional style -- map, filter, sum
    let total: f64 = prices.iter().sum();
    println!("Total: {:.2}", total);

    let above_30: Vec<f64> = prices.iter()
        .filter(|&&p| p > 30.0)
        .copied()
        .collect();
    println!("Items above 30: {:?}", above_30);

    let discounted: Vec<f64> = prices.iter()
        .map(|p| p * 0.8)  // 20% off
        .collect();
    println!("20% discount: {:?}", discounted);
}

Resultado:

TEXT 📖 Somente leitura
Prices: 29.9 49.9 15.5 99.0 8.8
With 10% tax: [32.89, 54.89, 17.05, 108.9, 9.68]
Item 0: 32.89
Item 1: 54.89
Item 2: 17.05
Item 3: 108.90
Item 4: 9.68
Total: 223.41
Items above 30: [32.89, 54.89, 108.9]
20% discount: [26.312, 43.912, 13.640000000000002, 87.12, 7.744]

O Vec oferece suporte a vários métodos de iteração: &v para iteração somente leitura e &mut v para modificação de elementos. Os métodos de estilo funcional .iter(), .map(), .filter() e .sum() tornam o processamento de dados conciso e elegante. .collect() converte um iterador de volta em um Vec.


▶ Exemplo 4: Conversão entre Vec e matrizes (Dificuldade ⭐⭐)

RUST
// ============================================
// Conversion between Vec and arrays
// ============================================

fn main() {
    // Array -> Vec: via .to_vec()
    let arr: [i32; 5] = [10, 20, 30, 40, 50];
    let vec_from_arr: Vec<i32> = arr.to_vec();
    println!("Array to Vec: {:?}", vec_from_arr);

    // Array -> Vec: via .iter().copied().collect()
    let vec_via_iter: Vec<i32> = arr.iter().copied().collect();
    println!("Via iter: {:?}", vec_via_iter);

    // Vec -> Array: via try_into() (returns Result)
    let vec_data = vec![1, 2, 3, 4];
    // let bad_array: [i32; 5] = vec_data.try_into().unwrap();  // PANIC: length mismatch
    let ok_array: [i32; 4] = vec_data.try_into().unwrap();
    println!("Vec to array: {:?}", ok_array);

    // Vec -> slice (zero-cost, no copy)
    let slice: &[i32] = &ok_array[1..3];
    println!("Slice of array: {:?}", slice);

    // Vec from iterator
    let squares: Vec<i32> = (1..=5).map(|x| x * x).collect();
    println!("Squares: {:?}", squares);

    // Vec from repeated value
    let repeated = vec!["hello"; 3];
    println!("Repeated: {:?}", repeated);
}

Resultado:

TEXT 📖 Somente leitura
Array to Vec: [10, 20, 30, 40, 50]
Via iter: [10, 20, 30, 40, 50]
Vec to array: [1, 2, 3, 4]
Slice of array: [20, 30]
Squares: [1, 4, 9, 16, 25]
Repeated: ["hello", "hello", "hello"]

Use .to_vec() para converter um array em um Vec. Use .try_into().unwrap() para converter um Vec em um array — os comprimentos devem ser iguais, caso contrário, ocorrerá um panic. Um Vec pode ser convertido em uma fatia sem custo algum usando &[T]. Criar um Vec a partir de um iterador usando .collect() é uma técnica comum.


▶ Exemplo 5: Exercício abrangente — Cesta de compras e cálculo de preço (Dificuldade ⭐⭐⭐)

RUST
// ============================================
// Comprehensive Example: Vec Insert, Delete, Update, Query + Functional Iteration
// ============================================

#[derive(Debug, Clone)]
struct Item {
    name: String,
    price: f64,
    quantity: u32,
}

impl Item {
    fn new(name: &str, price: f64, quantity: u32) -> Self {
        Item { name: name.to_string(), price, quantity }
    }
    fn subtotal(&self) -> f64 {
        self.price * self.quantity as f64
    }
}

fn print_cart(cart: &[Item]) {
    println!("{:<15} {:>8} {:>6} {:>10}", "Products", "Unit Price", "Quantity", "Subtotal");
    println!("{}", "-".repeat(42));
    for item in cart {
        println!("{:<15} {:>8.2} {:>6} {:>10.2}",
            item.name, item.price, item.quantity, item.subtotal());
    }
    let total: f64 = cart.iter().map(|i| i.subtotal()).sum();
    println!("{}", "-".repeat(42));
    println!("{:<15} {:>8} {:>6} {:>10.2}", "Total", "", "", total);
}

fn main() {
    let mut cart: Vec<Item> = Vec::new();
    cart.push(Item::new("Milk", 5.5, 2));
    cart.push(Item::new("Bread", 8.0, 1));
    cart.push(Item::new("Eggs", 12.5, 3));
    cart.push(Item::new("Cola", 3.0, 4));

    println!("=== Shopping Cart ===");
    print_cart(&cart);

    cart.retain(|i| i.name != "Cola");
    println!("\n--- Remove Cola after ---");
    print_cart(&cart);

    cart.push(Item::new("Butter", 15.0, 2));
    if let Some(eggs) = cart.iter_mut().find(|i| i.name == "Eggs") {
        eggs.quantity += 2;
    }
    println!("\n--- Add Butter + Add Eggs Quantity ---");
    print_cart(&cart);

    let total: f64 = cart.iter().map(|i| i.subtotal()).sum();
    let tax = total * 0.08;
    println!("\nBefore taxes: {:.2}, Tax(8%): {:.2}, Total due: {:.2}", total, tax, total + tax);

    let expensive: Vec<&Item> = cart.iter().filter(|i| i.price > 10.0).collect();
    println!("Unit Price > 10 Items priced at yuan: {:?}", expensive.iter().map(|i| &i.name).collect::<Vec<_>>());
}

Resultado:

TEXT 📖 Somente leitura
=== Shopping Cart ===
Products               Unit Price   Quantity       Subtotal
------------------------------------------
Milk              5.50      2      11.00
Bread             8.00      1       8.00
Eggs             12.50      3      37.50
Cola              3.00      4      12.00
------------------------------------------
Total                                68.50

--- Remove Cola after ---
Products               Unit Price   Quantity       Subtotal
------------------------------------------
Milk              5.50      2      11.00
Bread             8.00      1       8.00
Eggs             12.50      3      37.50
------------------------------------------
Total                                56.50

--- Add Butter + Add Eggs Quantity ---
Products               Unit Price   Quantity       Subtotal
------------------------------------------
Milk              5.50      2      11.00
Bread             8.00      1       8.00
Eggs             12.50      5      62.50
Butter           15.00      2      30.00
------------------------------------------
Total                               103.50

Before taxes: 103.50, Tax(8%): 8.28, Total due: 111.78
Unit Price > 10 Items priced at yuan: ["Eggs", "Butter"]

Este exemplo combina o uso de operações principais do Vec, como push, retain (exclusão condicional), iter_mut().find() (modificação condicional) e map/filter/sum (estatísticas funcionais). retain é mais adequado para exclusão em lote do que remove.


❓ Perguntas Frequentes

P: O que acontece quando o Vec é redimensionado? O desempenho é bom? R: Quando o Vec fica cheio, ele aloca um novo bloco de memória com o dobro do tamanho, copia os dados antigos para ele e libera a memória antiga. Após o cálculo da média, cada operação push continua sendo O(1) — pois a maioria das operações push não requer redimensionamento. Se você souber o tamanho com antecedência, use Vec::with_capacity(n) para evitar redimensionamentos múltiplos.

P: Como devo escolher entre Vec e uma matriz? R: Se o número exato de elementos for conhecido na hora da compilação e for pequeno, use uma matriz; se o número variar dinamicamente ou for desconhecido, use Vec. As matrizes são mais rápidas na pilha, enquanto o Vec é mais flexível no heap. Em geral, dê prioridade ao uso do Vec, a menos que haja requisitos específicos de desempenho ou de layout de memória.

P: Qual é a diferença entre vec!["a", "b"] e vec!["a"; 2]? R: O primeiro é uma lista de elementos (cada elemento é calculado independentemente), enquanto o segundo é uma duplicata do mesmo valor. vec![0; 5] cria 5 zeros (requer T: Clone). Se T não for Clone, apenas o método de lista pode ser usado.

P: Qual é a diferença entre .iter() e into_iter()? R: .iter() retorna uma referência (sem transferir a propriedade), enquanto into_iter() consome o Vec e retorna um iterador que detém a propriedade. .iter() O Vec permanece disponível após a iteração; into_iter() O Vec original não pode mais ser usado após a iteração.

P: Como os dados do Vec são armazenados no heap, o que a variável Vec na pilha contém? R: A pilha contém três valores usize: um ponteiro para os dados do heap, o comprimento (len) e a capacidade (capacity), totalizando 24 bytes (em um sistema de 64 bits). Os dados propriamente ditos estão no heap. Portanto, a própria variável Vec é muito pequena; copiá-la envolve simplesmente copiar esses 24 bytes de “ponteiros gordos”.


📖 Resumo


📝 Exercícios

  1. Dificuldade ⭐: Crie um Vec<i32> contendo os números de 1 a 10, use push para adicionar 11 e 12, depois use pop para remover os últimos 3 elementos e, por fim, imprima Vec.
  2. Dificuldade ⭐⭐: Escreva uma função fn remove_evens(v: &mut Vec<i32>) que remova todos os números pares de Vec e mantenha os ímpares. Teste-a em main usando vec![1, 2, 3, 4, 5, 6, 7, 8]; o resultado deve ser [1, 3, 5, 7].
  3. Dificuldade ⭐⭐⭐: Simule um programa de carrinho de compras. Defina um struct Item { name: String, price: f64, quantity: u32 }. Crie um carrinho de compras Vec<Item> e implemente o seguinte: adicionar itens, excluir itens pelo nome, modificar quantidades e imprimir o preço total do carrinho de compras. Demonstre o processo completo em main.
Web-Tutorial.com

Equipe Técnica Web-Tutorial

Uma plataforma de tutoriais mantida por diversos desenvolvedores. Cada tutorial é escrito e revisado por profissionais da área correspondente. Trabalhamos para manter nosso conteúdo preciso e confiável — se encontrar algum problema, avise-nos.

100%