O que é Vec<T>
Vec<T>, ou simplesmente “vetor”, é a coleção dinâmica mais usada em Rust. Ele armazena elementos do tipo T de forma contígua na memória heap, podendo crescer ou encolher conforme necessário. Internamente, um Vec mantém três informações: um ponteiro para os dados no heap, o tamanho atual (len) e a capacidade alocada (capacity).
Use Vec<T> sempre que precisar de uma lista de elementos cujo tamanho não é conhecido em tempo de compilação, ou que pode mudar durante a execução. É o equivalente em Rust ao ArrayList de Java, ao list de Python ou ao std::vector de C++. Para sequências de tamanho fixo conhecidas em compilação, considere usar arrays [T; N] ou slices.
Criando Vetores
fn main() {
// Vetor vazio (precisa de anotação de tipo ou uso posterior)
let mut vazio: Vec<i32> = Vec::new();
vazio.push(1);
// Usando a macro vec!
let numeros = vec![1, 2, 3, 4, 5];
// Repetindo um valor
let zeros = vec![0; 10]; // 10 zeros
// Com capacidade pré-alocada
let mut com_capacidade = Vec::with_capacity(100);
com_capacidade.push(42);
println!("Len: {}, Capacidade: {}", com_capacidade.len(), com_capacidade.capacity());
// Len: 1, Capacidade: 100
// A partir de um iterador
let pares: Vec<i32> = (0..10).filter(|x| x % 2 == 0).collect();
println!("{pares:?}"); // [0, 2, 4, 6, 8]
// A partir de um array
let array = [10, 20, 30];
let de_array = array.to_vec();
// A partir de um slice
let slice = &numeros[1..4];
let de_slice = slice.to_vec();
println!("{numeros:?} {zeros:?} {de_array:?} {de_slice:?}");
}
Tabela de Métodos Principais
| Método | Descrição | Exemplo |
|---|---|---|
push(valor) | Adiciona ao final | v.push(10) |
pop() | Remove e retorna o último | v.pop() → Some(10) |
insert(i, valor) | Insere na posição i | v.insert(0, 99) |
remove(i) | Remove e retorna o elemento na posição i | v.remove(0) |
swap_remove(i) | Remove trocando com o último (O(1)) | v.swap_remove(0) |
len() | Número de elementos | v.len() → 5 |
is_empty() | Verifica se está vazio | v.is_empty() |
capacity() | Capacidade alocada | v.capacity() |
contains(&val) | Verifica se contém o valor | v.contains(&3) |
sort() | Ordena in-place | v.sort() |
sort_by(f) | Ordena com comparador personalizado | v.sort_by(|a, b| b.cmp(a)) |
dedup() | Remove duplicatas consecutivas | v.dedup() |
retain(f) | Mantém apenas elementos que satisfazem f | v.retain(|x| *x > 0) |
extend(iter) | Adiciona elementos de um iterador | v.extend([4, 5, 6]) |
truncate(n) | Mantém apenas os primeiros n | v.truncate(3) |
clear() | Remove todos os elementos | v.clear() |
iter() | Iterador de referências | v.iter() |
iter_mut() | Iterador de referências mutáveis | v.iter_mut() |
windows(n) | Janelas deslizantes de tamanho n | v.windows(2) |
chunks(n) | Divide em pedaços de tamanho n | v.chunks(3) |
split(f) | Divide onde f retorna true | v.split(|x| *x == 0) |
binary_search(&val) | Busca binária (requer vetor ordenado) | v.binary_search(&5) |
as_slice() | Converte para &[T] | v.as_slice() |
Exemplos Práticos
1. Filtrando e Transformando Dados
fn main() {
let temperaturas = vec![22.5, 35.1, 18.3, 40.0, 28.7, 15.2, 33.8];
// Filtrar temperaturas acima de 30°C
let quentes: Vec<f64> = temperaturas
.iter()
.copied()
.filter(|&t| t > 30.0)
.collect();
println!("Acima de 30°C: {quentes:?}"); // [35.1, 40.0, 33.8]
// Converter Celsius para Fahrenheit
let fahrenheit: Vec<f64> = temperaturas
.iter()
.map(|c| c * 9.0 / 5.0 + 32.0)
.collect();
println!("Fahrenheit: {fahrenheit:.1?}");
// Média das temperaturas
let soma: f64 = temperaturas.iter().sum();
let media = soma / temperaturas.len() as f64;
println!("Média: {media:.1}°C"); // Média: 27.7°C
}
2. Ordenação Personalizada
#[derive(Debug)]
struct Aluno {
nome: String,
nota: f64,
}
fn main() {
let mut alunos = vec![
Aluno { nome: "Ana".into(), nota: 8.5 },
Aluno { nome: "Bruno".into(), nota: 9.2 },
Aluno { nome: "Carlos".into(), nota: 7.8 },
Aluno { nome: "Diana".into(), nota: 9.2 },
];
// Ordenar por nota (decrescente), depois por nome (crescente)
alunos.sort_by(|a, b| {
b.nota.partial_cmp(&a.nota)
.unwrap()
.then(a.nome.cmp(&b.nome))
});
for aluno in &alunos {
println!("{}: {:.1}", aluno.nome, aluno.nota);
}
// Bruno: 9.2
// Diana: 9.2
// Ana: 8.5
// Carlos: 7.8
}
3. Removendo Duplicatas
fn main() {
let mut numeros = vec![3, 1, 4, 1, 5, 9, 2, 6, 5, 3, 5];
// dedup só remove duplicatas CONSECUTIVAS, então ordene primeiro
numeros.sort();
numeros.dedup();
println!("Sem duplicatas: {numeros:?}"); // [1, 2, 3, 4, 5, 6, 9]
// Alternativa: usando um HashSet para preservar a ordem original
use std::collections::HashSet;
let numeros2 = vec![3, 1, 4, 1, 5, 9, 2, 6, 5, 3, 5];
let mut vistos = HashSet::new();
let unicos: Vec<i32> = numeros2
.into_iter()
.filter(|x| vistos.insert(*x))
.collect();
println!("Únicos (ordem preservada): {unicos:?}"); // [3, 1, 4, 5, 9, 2, 6]
}
4. Usando retain para Filtrar In-Place
fn main() {
let mut tarefas = vec![
("Comprar leite", true),
("Estudar Rust", false),
("Lavar louça", true),
("Ler livro", false),
("Fazer exercício", false),
];
// Remover tarefas já concluídas
tarefas.retain(|(_, concluida)| !concluida);
println!("Tarefas pendentes:");
for (tarefa, _) in &tarefas {
println!(" - {tarefa}");
}
// - Estudar Rust
// - Ler livro
// - Fazer exercício
}
5. Janelas Deslizantes e Chunks
fn main() {
let dados = vec![10, 20, 30, 40, 50, 60, 70, 80, 90, 100];
// Média móvel com janela de 3
let medias: Vec<f64> = dados
.windows(3)
.map(|janela| janela.iter().sum::<i32>() as f64 / 3.0)
.collect();
println!("Médias móveis: {medias:.1?}");
// Processar em lotes de 4
for (i, lote) in dados.chunks(4).enumerate() {
let soma: i32 = lote.iter().sum();
println!("Lote {i}: {lote:?} (soma: {soma})");
}
}
Dicas de Performance e Armadilhas
Use
with_capacity: Se você sabe (ou consegue estimar) quantos elementos vai adicionar, useVec::with_capacity(n)para evitar realocações. Cada realocação copia todos os dados para um bloco de memória maior.swap_removevsremove: Oremove(i)desloca todos os elementos posteriores (O(n)), enquantoswap_remove(i)troca o elemento com o último e fazpop(O(1)). Useswap_removequando a ordem não importa.Indexação fora dos limites: Acessar
v[i]ondei >= v.len()causa panic. Usev.get(i)para obter umOption<&T>seguro.deduprequer ordenação prévia: O métododedup()só remove duplicatas consecutivas. Para remover todas as duplicatas, ordene o vetor primeiro comsort().Cuidado com
clone()de vetores grandes: Clonar umVeccopia todos os elementos. Prefira usar referências (&Vec<T>ou, melhor ainda,&[T]) quando possível.drainpara extrair subconjuntos: Usev.drain(range)para remover e consumir uma faixa de elementos sem realocar, retornando um iterador.
Veja Também
- Ordenar Vetores em Rust — receitas de ordenação personalizada
- Filtrar Vetores em Rust — padrões de filtragem com exemplos
- Slices (&[T]) — referências a partes de um vetor
- Iterator Trait — para transformar e processar vetores
- HashMap<K,V> — quando precisar de acesso por chave
- String e &str — Vec de caracteres e bytes
- Cheatsheet Rust — referência rápida de sintaxe
- Documentação oficial — std::vec::Vec