<h2>O que é Box<T> e Por Que Usar?</h2>
<p>Box<T> é um tipo de dado inteligente (smart pointer) em Rust que aloca valores no heap em vez de na stack. A stack é uma região de memória rápida mas limitada; o heap é maior mas mais lenta. Quando você tem dados de tamanho desconhecido em tempo de compilação ou precisa passar propriedade entre escopos, Box<T> é a ferramenta certa.</p>
<p>Rust é uma linguagem de propriedade. Por padrão, valores vivem na stack e são movidos quando atribuídos a novas variáveis. Box<T> envolve um valor e permite que você o trate como um ponteiro — mantendo a semântica de propriedade intacta. Quando o Box sai do escopo, o valor no heap é automaticamente desalocado. Não há garbage collector; a memória é gerenciada por regras determinísticas.</p>
<pre><code class="language-rust">fn main() {
// Valor na stack
let x = 5;
// Valor no heap via Box
let y = Box::new(5);
println!("x = {}", x); // 5
println!("y = {}", y); // 5 (Box dereferencia automaticamente em println!)
// Tamanho em bytes
println!("Size of x: {}", std::mem::size_of_val(&x)); // 8 (i32)
println!("Size of y: {}", std::mem::size_of_val(&y)); // 8 (ponteiro)
}</code></pre>
<h2>Alocação e Propriedade</h2>
<p>Quando você cria um Box com <code>Box::new(valor)</code>, Rust aloca memória no heap e retorna um Box que "possui" esse valor. A propriedade funciona normalmente: quando o Box sai do escopo, o valor é desalocado. Você pode transferir propriedade movendo o Box, ou emprestar uma referência usando <code>&box</code> ou <code>&*box</code>.</p>
<p>Este exemplo mostra transferência de propriedade e borrowing:</p>
<pre><code class="language-rust">struct Pessoa {
nome: String,
idade: u32,
}
fn imprime_pessoa(p: &Pessoa) {
println!("{}, {} anos", p.nome, p.idade);
}
fn consome_pessoa(p: Box<Pessoa>) {
println!("Consumindo: {}", p.nome);
// Box e seu conteúdo são desalocados aqui
}
fn main() {
let pessoa = Box::new(Pessoa {
nome: "Alice".to_string(),
idade: 30,
});
// Emprestando referência - pessoa ainda é dona do Box
imprime_pessoa(&pessoa);
// Transferindo propriedade - pessoa perde o Box
consome_pessoa(pessoa);
// println!("{}", pessoa.nome); // ERRO: pessoa não existe mais
}</code></pre>
<h2>Casos de Uso Práticos</h2>
<h3>Dados de Tamanho Desconhecido</h3>
<p>Traits em Rust não têm tamanho conhecido em tempo de compilação. Se você quer armazenar diferentes tipos implementando a mesma trait, use <code>Box<dyn Trait></code>:</p>
<pre><code class="language-rust">trait Animal {
fn fazer_som(&self);
}
struct Cachorro;
struct Gato;
impl Animal for Cachorro {
fn fazer_som(&self) {
println!("Au au!");
}
}
impl Animal for Gato {
fn fazer_som(&self) {
println!("Miau!");
}
}
fn main() {
let animais: Vec<Box<dyn Animal>> = vec![
Box::new(Cachorro),
Box::new(Gato),
Box::new(Cachorro),
];
for animal in animais {
animal.fazer_som();
}
}</code></pre>
<h3>Estruturas Recursivas</h3>
<p>Tipos recursivos (como árvores ou listas ligadas) precisam de Box para quebrar a dependência circular:</p>
<pre><code class="language-rust">#[derive(Debug)]
enum Nodo {
Vazio,
Com(i32, Box<Nodo>),
}
fn main() {
let lista = Nodo::Com(1, Box::new(
Nodo::Com(2, Box::new(
Nodo::Com(3, Box::new(Nodo::Vazio))
))
));
println!("{:?}", lista);
// Com(1, Com(2, Com(3, Vazio)))
}</code></pre>
<h3>Otimização de Performance</h3>
<p>Valores grandes podem degradar performance se copiados frequentemente. Box evita cópias mantendo um ponteiro:</p>
<pre><code class="language-rust">struct DadosGrandes {
vetor: Vec<u32>,
}
impl DadosGrandes {
fn new() -> Self {
DadosGrandes {
vetor: vec![0; 1_000_000],
}
}
}
fn processa(dados: Box<DadosGrandes>) {
println!("Processando {} elementos", dados.vetor.len());
}
fn main() {
let dados = Box::new(DadosGrandes::new());
processa(dados); // Apenas o ponteiro é movido, não os milhões de elementos
}</code></pre>
<h2>Dereferência e Coerção</h2>
<p>Box implementa o trait <code>Deref</code>, permitindo acessar o valor através do operador <code>*</code> ou via coerção automática. Rust converte <code>Box<T></code> em <code>&T</code> automaticamente em contextos onde uma referência é esperada:</p>
<pre><code class="language-rust">fn main() {
let boxed = Box::new(String::from("Rust"));
// Dereferência explícita
println!("Comprimento: {}", (*boxed).len());
// Dereferência implícita (coerção)
println!("Maiúsculas: {}", boxed.to_uppercase());
// Modificação via DerefMut
let mut numero = Box::new(42);
*numero += 8;
println!("Número: {}", numero);
}</code></pre>
<p>Box também implementa <code>DerefMut</code>, permitindo mutabilidade. Se você precisa modificar o valor dentro, declare o Box como <code>mut</code>:</p>
<pre><code class="language-rust">fn incrementa(n: &mut i32) {
*n += 1;
}
fn main() {
let mut valor = Box::new(10);
incrementa(&mut valor);
println!("{}", valor); // 11
}</code></pre>
<h2>Conclusão</h2>
<p>Box<T> é fundamental em Rust para alocação explícita no heap. Use-o para: (1) <strong>armazenar traits dinamicamente</strong> com <code>dyn</code>, eliminando dependências de tamanho em tempo de compilação; (2) <strong>criar estruturas recursivas</strong> quebrando ciclos de definição; (3) <strong>otimizar performance</strong> evitando cópias de dados grandes. Rust garante segurança de memória: quando o Box sai do escopo, seu conteúdo é automaticamente liberado.</p>
<h2>Referências</h2>
<ul>
<li><a href="https://doc.rust-lang.org/book/ch15-01-box.html" target="_blank" rel="noopener noreferrer">The Rust Book - Box<T></a></li>
<li><a href="https://doc.rust-lang.org/std/boxed/struct.Box.html" target="_blank" rel="noopener noreferrer">Documentação Oficial: std::boxed::Box</a></li>
<li><a href="https://github.com/rust-lang/rustlings" target="_blank" rel="noopener noreferrer">Rustlings - Smart Pointers</a></li>
<li><a href="https://doc.rust-lang.org/rust-by-example/std/box.html" target="_blank" rel="noopener noreferrer">Rust by Example - Box and Deref</a></li>
<li><a href="https://www.oreilly.com/library/view/programming-rust/9781491927281/" target="_blank" rel="noopener noreferrer">Programming Rust - Jim Blandy & Jason Orendorff</a></li>
</ul>