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
- Criar matrizes dinâmicas usando a macro
vec!eVec::new() - Use as funções push e pop para adicionar ou remover elementos do final
- Use
inserteremovepara adicionar ou remover elementos no meio - Compreender a diferença entre capacidade e comprimento
- Percorrer e iterar sobre vetores, e converter entre vetores e matrizes
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:
// 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
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;pushadicione elementos (o array se redimensiona automaticamente);popremova 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
graph LR
A[Vec<T> 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 ⭐)
// ============================================
// 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:
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"]ouvec.pushacrescenta um elemento ao final;popretira um elemento do final (retornaOption<T>).len()retorna o número de elementos da lista.
▶ Exemplo 2: Inserção/remoção e gerenciamento de capacidade (Dificuldade ⭐⭐)
// ============================================
// 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:
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 quelen), eshrink_to_fit()libera o espaço excedente..get()Garante um acesso seguro; em caso de acesso fora dos limites, retornaNoneem vez de causar um panic.
▶ Exemplo 3: Métodos de percorrimento e iteração de vetores (Dificuldade ⭐⭐)
// ============================================
// 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:
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:
&vpara iteração somente leitura e&mut vpara 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 ⭐⭐)
// ============================================
// 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:
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 ⭐⭐⭐)
// ============================================
// 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:
=== 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) emap/filter/sum(estatísticas funcionais).retainé mais adequado para exclusão em lote do queremove.
❓ 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
pushcontinua sendo O(1) — pois a maioria das operaçõespushnão requer redimensionamento. Se você souber o tamanho com antecedência, useVec::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"]evec!["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
Vec<T>é uma matriz alocada dinamicamente na pilha (heap) que pode ter seu tamanho alterado em tempo de execução- Método de criação:
Vec::new(),vec![],Vec::with_capacity(n) - Operações na cauda:
pushAdicionar (O(1) com balanceamento de carga),popRemover (O(1)) - Operação intermediária:
insert/remove(O(n), os dados devem ser deslocados) - Capacidade x Comprimento:
capacityé o espaço alocado;lené o número real de elementos;shrink_to_fitlibera o excesso de memória - Os Vecs e as matrizes podem ser convertidos entre si, e os Vecs podem ser convertidos em fatias sem custo adicional
&[T]
📝 Exercícios
- Dificuldade ⭐: Crie um
Vec<i32>contendo os números de 1 a 10, usepushpara adicionar 11 e 12, depois usepoppara remover os últimos 3 elementos e, por fim, imprima Vec. - 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 emmainusandovec![1, 2, 3, 4, 5, 6, 7, 8]; o resultado deve ser[1, 3, 5, 7]. - Dificuldade ⭐⭐⭐: Simule um programa de carrinho de compras. Defina um
struct Item { name: String, price: f64, quantity: u32 }. Crie um carrinho de comprasVec<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 emmain.