<h2>O que é Interior Mutability?</h2>
<p>Interior mutability é um padrão de design em Rust que permite modificar dados através de uma referência imutável. Normalmente, Rust impõe que você tenha <em>ou</em> uma referência mutável exclusiva (<code>&mut T</code>) <em>ou</em> várias referências imutáveis (<code>&T</code>), nunca ambas simultaneamente. Interior mutability quebra essa regra em tempo de execução, permitindo mutações controladas sem violar a segurança de memória. Isso é essencial quando você precisa compartilhar propriedade sobre dados e ainda assim modificá-los — um cenário comum em estruturas como gráficos, caches ou callbacks.</p>
<p>O custo dessa flexibilidade é a verificação em tempo de execução. Enquanto o borrow checker valida referências em compile-time, interior mutability valida em runtime, podendo causar panic se as regras forem violadas. <code>RefCell<T></code> é a ferramenta mais prática para isso: fornece mutabilidade interior com verificação dinâmica de borrowing.</p>
<h2>RefCell<T>: Estrutura e Funcionamento</h2>
<p><code>RefCell<T></code> é um wrapper que armazena um valor <code>T</code> e mantém controle sobre quantas referências imutáveis (<code>Ref<T></code>) e mutáveis (<code>RefMut<T></code>) existem em tempo de execução. Diferentemente de <code>Box<T></code> que apenas aloca memória, <code>RefCell<T></code> adiciona metadados para rastrear empréstimos.</p>
<pre><code class="language-rust">use std::cell::RefCell;
#[derive(Debug)]
struct Usuario {
nome: String,
saldo: RefCell<i32>,
}
impl Usuario {
fn novo(nome: String, saldo: i32) -> Self {
Usuario {
nome,
saldo: RefCell::new(saldo),
}
}
fn depositar(&self, valor: i32) {
// &self é imutável, mas podemos mutar saldo através de RefCell
let mut saldo = self.saldo.borrow_mut();
*saldo += valor;
}
fn consultar_saldo(&self) -> i32 {
*self.saldo.borrow()
}
}
fn main() {
let usuario = Usuario::novo("Alice".to_string(), 100);
usuario.depositar(50);
println!("Saldo: {}", usuario.consultar_saldo()); // Saldo: 150
}</code></pre>
<p>Dois métodos são centrais: <code>borrow()</code> retorna <code>Ref<T></code> (referência imutável temporária) e <code>borrow_mut()</code> retorna <code>RefMut<T></code> (referência mutável temporária). Estas são liberadas quando saem de escopo. Se você tentar fazer <code>borrow_mut()</code> enquanto um <code>borrow()</code> ativo existe, o programa faz panic — justamente a validação em tempo de execução.</p>
<h2>Casos de Uso Práticos</h2>
<h3>Cache e Lazy Evaluation</h3>
<p>Um uso comum é implementar valores calculados sob demanda:</p>
<pre><code class="language-rust">use std::cell::RefCell;
struct Computacao {
entrada: i32,
resultado: RefCell<Option<i32>>,
}
impl Computacao {
fn novo(entrada: i32) -> Self {
Computacao {
entrada,
resultado: RefCell::new(None),
}
}
fn calcular(&self) -> i32 {
let mut res = self.resultado.borrow_mut();
if res.is_none() {
println!("Calculando...");
res = Some(self.entrada 2);
}
res.unwrap()
}
}
fn main() {
let comp = Computacao::novo(10);
println!("{}", comp.calcular()); // Calcula: 20
println!("{}", comp.calcular()); // Usa cache: 20
}</code></pre>
<h3>Observadores e Callbacks</h3>
<p>Estruturas que precisam notificar múltiplos observadores muitas vezes usam <code>RefCell</code>:</p>
<pre><code class="language-rust">use std::cell::RefCell;
struct Modelo {
dados: RefCell<String>,
observadores: RefCell<Vec<Box<dyn Fn(&str)>>>,
}
impl Modelo {
fn novo() -> Self {
Modelo {
dados: RefCell::new(String::new()),
observadores: RefCell::new(Vec::new()),
}
}
fn registrar_observador(&self, callback: Box<dyn Fn(&str)>) {
self.observadores.borrow_mut().push(callback);
}
fn atualizar(&self, novo_valor: String) {
*self.dados.borrow_mut() = novo_valor.clone();
for observador in self.observadores.borrow().iter() {
observador(&novo_valor);
}
}
}
fn main() {
let modelo = Modelo::novo();
modelo.registrar_observador(Box::new(|v| println!("Notificado: {}", v)));
modelo.atualizar("Nova dados".to_string());
}</code></pre>
<h2>Alternativas e Quando Usar</h2>
<p><code>RefCell<T></code> não é a única solução. <code>Cell<T></code> é semelhante mas não oferece referências — apenas cópia/substituição completa de valores, útil para tipos pequenos como inteiros. <code>Mutex<T></code> é thread-safe e apropriado para ambientes concorrentes. <code>Arc<T></code> combina contagem de referências com <code>Mutex<T></code> para compartilhamento seguro entre threads.</p>
<p>Escolha <code>RefCell<T></code> quando: (1) você está em single-thread, (2) precisa mutar campos dentro de um método que recebe <code>&self</code>, e (3) está confiante que seus empréstimos em tempo de execução serão válidos. Evite quando há risco de panics frequentes — eles indicam design problemático. Se frequentemente você tenta fazer múltiplos <code>borrow_mut()</code> simultâneos, reconsidere a arquitetura.</p>
<pre><code class="language-rust"></code></pre>
<h2>Conclusão</h2>
<p><code>RefCell<T></code> e interior mutability são ferramentas poderosas que desbloqueiam padrões de design impossíveis com as regras normais de borrowing. Eles permitem mutações através de referências imutáveis, pagando o preço com verificações em runtime. Três pontos-chave: primeiro, use <code>RefCell<T></code> para contornar limitações do borrow checker em código single-thread, mantendo segurança de memória; segundo, sempre estruture seu código para evitar múltiplos empréstimos mutáveis simultâneos — panics indicam bugs; terceiro, considere se sua arquitetura realmente exige interior mutability ou se uma refatoração resolveria melhor.</p>
<h2>Referências</h2>
<ul>
<li><a href="https://doc.rust-lang.org/book/ch15-05-interior-mutability.html" target="_blank" rel="noopener noreferrer">Rust Book - RefCell and Interior Mutability</a></li>
<li><a href="https://doc.rust-lang.org/std/cell/struct.RefCell.html" target="_blank" rel="noopener noreferrer">Documentação Oficial std::cell::RefCell</a></li>
<li><a href="https://doc.rust-lang.org/nomicon/interior-mutability.html" target="_blank" rel="noopener noreferrer">The Rustonomicon - Interior Mutability</a></li>
<li><a href="https://doc.rust-lang.org/rust-by-example/std/cell.html" target="_blank" rel="noopener noreferrer">Rust by Example - Cell and RefCell</a></li>
</ul>