Rust

Guia Completo de Vec<T> em Rust: O Array Dinâmico da Biblioteca Padrão

7 min de leitura

Guia Completo de Vec<T> em Rust: O Array Dinâmico da Biblioteca Padrão

Vec : Entendendo o Array Dinâmico Fundamental Vec é a estrutura de dados mais versátil da Rust: um array alocado na heap que cresce e encolhe dinamicamente conforme necessário. Diferentemente de arrays primitivos como , que têm tamanho fixo e conhecido em tempo de compilação, Vec permite que você trabalhe com coleções cujo tamanho é desconhecido ou muda durante a execução. Internamente, Vec mantém três informações críticas: um ponteiro para os dados na heap, a capacidade (quantos elementos cabem sem realocação) e o comprimento (quantos elementos estão realmente armazenados). Essa distinção entre capacidade e comprimento é essencial para entender a performance e o comportamento de Vec. Criação, Inicialização e Operações Básicas Existem várias formas ergonômicas de criar um Vec em Rust. A macro é a mais prática para inicializar com valores conhecidos, enquanto cria um vetor vazio. O método é crucial quando você sabe antecipadamente quantos elementos será necessário armazenar, evitando realocações desnecessárias. As operações de indexação usam , mas

<h2>Vec&lt;T&gt;: Entendendo o Array Dinâmico Fundamental</h2>

<p>Vec&lt;T&gt; é a estrutura de dados mais versátil da Rust: um array alocado na heap que cresce e encolhe dinamicamente conforme necessário. Diferentemente de arrays primitivos como <code>[T; n]</code>, que têm tamanho fixo e conhecido em tempo de compilação, Vec permite que você trabalhe com coleções cujo tamanho é desconhecido ou muda durante a execução.</p>

<p>Internamente, Vec mantém três informações críticas: um ponteiro para os dados na heap, a capacidade (quantos elementos cabem sem realocação) e o comprimento (quantos elementos estão realmente armazenados). Essa distinção entre capacidade e comprimento é essencial para entender a performance e o comportamento de Vec.</p>

<pre><code class="language-rust">fn main() {

// Criando um Vec vazio

let mut numeros: Vec&lt;i32&gt; = Vec::new();

// Adicionando elementos

numeros.push(10);

numeros.push(20);

numeros.push(30);

println!(&quot;Vec: {:?}&quot;, numeros);

println!(&quot;Comprimento: {}&quot;, numeros.len());

println!(&quot;Capacidade: {}&quot;, numeros.capacity());

}</code></pre>

<h2>Criação, Inicialização e Operações Básicas</h2>

<p>Existem várias formas ergonômicas de criar um Vec em Rust. A macro <code>vec!</code> é a mais prática para inicializar com valores conhecidos, enquanto <code>Vec::new()</code> cria um vetor vazio. O método <code>with_capacity()</code> é crucial quando você sabe antecipadamente quantos elementos será necessário armazenar, evitando realocações desnecessárias.</p>

<pre><code class="language-rust">fn main() {

// Usando macro vec!

let mut cores = vec![&quot;vermelho&quot;, &quot;azul&quot;, &quot;verde&quot;];

// Pré-alocando capacidade

let mut dados: Vec&lt;String&gt; = Vec::with_capacity(100);

// Acessando elementos

println!(&quot;Primeira cor: {}&quot;, cores[0]);

// Iterando

for cor in &amp;cores {

println!(&quot;{}&quot;, cor);

}

// Modificando

cores.push(&quot;amarelo&quot;);

cores[0] = &quot;laranja&quot;;

// Removendo

let removido = cores.pop(); // Remove o último

println!(&quot;Removido: {:?}&quot;, removido);

}</code></pre>

<p>As operações de indexação usam <code>[]</code>, mas falham em runtime se o índice estiver fora dos limites. Para segurança, use <code>get()</code>, que retorna <code>Option&lt;&amp;T&gt;</code>. O método <code>pop()</code> remove e retorna o último elemento, enquanto <code>insert()</code> e <code>remove()</code> trabalham com índices específicos — porém são custosos para vetores grandes porque requerem realocação de memória.</p>

<h2>Propriedade, Empréstimo e Iteração Eficiente</h2>

<p>A relação entre Vec e o sistema de propriedade (ownership) de Rust é onde muitos iniciantes enfrentam dificuldades. Quando você passa um Vec para uma função sem usar referência, a propriedade é transferida e a variável original fica inacessível. Use <code>&amp;vec</code> para empréstimos imutáveis e <code>&amp;mut vec</code> para mutáveis.</p>

<pre><code class="language-rust">fn processar_vetor(vec: &amp;[i32]) -&gt; i32 {

vec.iter().sum()

}

fn duplicar_elementos(vec: &amp;mut Vec&lt;i32&gt;) {

for elemento in vec.iter_mut() {

elemento = 2;

}

}

fn main() {

let mut numeros = vec![1, 2, 3, 4, 5];

let soma = processar_vetor(&amp;numeros);

println!(&quot;Soma: {}&quot;, soma);

duplicar_elementos(&amp;mut numeros);

println!(&quot;Duplicados: {:?}&quot;, numeros);

// Iteração eficiente com into_iter (consome o vetor)

let palavras = vec![&quot;hello&quot;, &quot;world&quot;];

for palavra in palavras {

println!(&quot;{}&quot;, palavra);

}

// &#039;palavras&#039; não está mais acessível aqui

}</code></pre>

<p>A escolha entre <code>iter()</code>, <code>iter_mut()</code> e <code>into_iter()</code> é fundamental. Use <code>iter()</code> para não modificar e manter a propriedade; <code>iter_mut()</code> para modificar in-place; e <code>into_iter()</code> quando quiser consumir o vetor e obter a propriedade dos elementos. Operações que consomem o vetor como <code>into_iter()</code> são geralmente mais eficientes porque não precisam gerenciar referências.</p>

<h2>Performance, Alocação de Memória e Boas Práticas</h2>

<p>Vec crescer dinamicamente tem um custo: quando a capacidade é excedida, ele realoca a memória — copiando todos os elementos para um novo bloco maior na heap. Essa é uma operação O(n) que deve ser evitada ao máximo. Se você sabe que precisará armazenar 10.000 elementos, aloque essa capacidade desde o início com <code>Vec::with_capacity(10_000)</code>.</p>

<pre><code class="language-rust">fn main() {

// Ineficiente: múltiplas realocações

let mut lento = Vec::new();

for i in 0..100_000 {

lento.push(i);

}

// Eficiente: uma alocação única

let mut rapido = Vec::with_capacity(100_000);

for i in 0..100_000 {

rapido.push(i);

}

// Reserve espaço adicional se necessário

let mut reservado = vec![1, 2, 3];

reservado.reserve(1000);

// Métodos úteis

println!(&quot;Está vazio? {}&quot;, reservado.is_empty());

reservado.clear(); // Remove todos sem deallocar

println!(&quot;Após clear: len={}, capacity={}&quot;,

reservado.len(),

reservado.capacity());

}</code></pre>

<p>Métodos como <code>reserve()</code> pré-alocam espaço sem adicionar elementos; <code>clear()</code> remove todos os itens mas mantém a capacidade; e <code>shrink_to_fit()</code> reduce a capacidade ao comprimento atual, útil quando você sabe que não adicionará mais elementos. Use slices (<code>&amp;[T]</code>) em assinaturas de funções em vez de <code>&amp;Vec&lt;T&gt;</code> — slices são mais flexíveis e aceitam tanto referências para vetores quanto para arrays primitivos.</p>

<h2>Conclusão</h2>

<p>Vec&lt;T&gt; é a espinha dorsal de estruturas de dados complexas em Rust. Os três conceitos essenciais que você dominou aqui são: (1) a distinção entre capacidade e comprimento, que determina a eficiência de suas operações; (2) o sistema de propriedade e empréstimo, que garante segurança de memória sem garbage collector; (3) a importância de pré-alocar capacidade quando o tamanho final é conhecido. Domine essas lições e você terá ferramentas para escrever código Rust rápido e seguro.</p>

<h2>Referências</h2>

<ul>

<li><a href="https://doc.rust-lang.org/std/vec/struct.Vec.html" target="_blank" rel="noopener noreferrer">The Rust Standard Library: Vec&lt;T&gt;</a></li>

<li><a href="https://doc.rust-lang.org/book/ch08-01-vectors.html" target="_blank" rel="noopener noreferrer">The Rust Programming Language - Chapter 8: Common Collections</a></li>

<li><a href="https://doc.rust-lang.org/rust-by-example/std/vec.html" target="_blank" rel="noopener noreferrer">Rust By Example: Vectors</a></li>

<li><a href="https://doc.rust-lang.org/nomicon/layout.html" target="_blank" rel="noopener noreferrer">The Rustonomicon: Memory Layout</a></li>

<li><a href="https://www.oreilly.com/library/view/programming-rust-2nd/9781492052586/" target="_blank" rel="noopener noreferrer">Programming Rust: Fast Systems Programming - Jim Blandy &amp; Jason Orendorff (O&#039;Reilly Media)</a></li>

</ul>

Comentários

Mais em Rust

Guia Completo de Stack vs Heap em Rust: Como a Memória é Gerenciada
Guia Completo de Stack vs Heap em Rust: Como a Memória é Gerenciada

Stack vs Heap em Rust: Como a Memória é Gerenciada O que são Stack e Heap? St...

Dominando Mutex<T> e RwLock<T> em Rust: Exclusão Mútua Segura em Projetos Reais
Dominando Mutex<T> e RwLock<T> em Rust: Exclusão Mútua Segura em Projetos Reais

Sincronização em Rust: Por que Mutex e RwLock Importam A segurança de memória...

Dominando Rc<T> e Arc<T> em Rust: Contagem de Referências em Projetos Reais
Dominando Rc<T> e Arc<T> em Rust: Contagem de Referências em Projetos Reais

Rc : Contagem de Referências em Single-Thread (Reference Counting) é um tipo...