Padrões de Mutabilidade Interna
Mutabilidade interna permite que você modifique dados através de referências compartilhadas quando as regras de empréstimo em tempo de execução ou a sincronização substituem a exclusividade em tempo de compilação.
Receita
use std::cell::RefCell;
let cache = RefCell::new(HashMap::new());
cache.borrow_mut().insert("k", 1);Quando usar isso: Grafos com aliasing, caches de thread única ou contadores compartilhados com Mutex/Atomic.
Exemplo de Trabalho
use std::sync::{Arc, Mutex};
struct AppState {
counter: Mutex<u64>,
}
async fn handler(state: Arc<AppState>) {
let mut n = state.counter.lock().unwrap();
*n += 1;
}O que isso demonstra:
RefCellpara mutabilidade interna de thread única (pânico de empréstimo em tempo de execução se violado)Mutexpara mutação compartilhada multi-threadCellapenas para tiposCopyArc<Mutex<T>>comum em estado compartilhado do Axum (prefiratokio::sync::Mutexem async)
Análise Detalhada
| Tipo | Threads | Pânico em conflito |
|---|---|---|
Cell | Não | Não (apenas Copy) |
RefCell | Não | Sim (empréstimo) |
Mutex | Sim | Erro de poison |
RwLock | Sim | Erro de poison |
Atomic* | Sim | Não |
Prefira passagem de mensagens ou mutação de propriedade antes de Rc<RefCell<_>>.
Armadilhas
Rc<RefCell>em todo lugar - pânicos em tempo de execução e grafo emaranhado. Correção: arena + índices ou propriedade única.Mutexentreawait- problemas deSende deadlocks. Correção:tokio::sync::Mutex; escopo do lock mínimo, semawaitenquanto segurastd::sync::Mutex.unwrapem poison de lock - esconde bugs. Correção: mapeie o erro de poison ou uselock().expect("msg")com uma política.RefCellem tarefaasync- não éSync. Correção: não coloqueRefCellemArccompartilhado entre threads.- Mutação oculta em método
&self- API surpreendente. Correção: documente a thread-safety e a mutação na documentação do método.
Alternativas
| Alternativa | Use Quando | Não Use Quando |
|---|---|---|
Propriedade mut | Dono único | Cache compartilhado necessário |
| Canais | Produtor/consumidor | Estado compartilhado de granularidade fina |
DashMap | Mapa concorrente | Simples thread única |
FAQs
RefCell vs Mutex em thread única?
RefCell é mais barato; nenhuma thread está envolvida.
tokio Mutex vs std?
tokio::sync::Mutex é amigável para await; std::sync::Mutex bloqueia o executor se mantido durante um await.
mutabilidade interna em trait?
Métodos &self que modificam um Mutex interno são um padrão comum.
Cell para flags booleanas?
Sim, para alternâncias em thread única.
OnceCell interior?
Inicialização preguiçosa sem referência mut após a inicialização; padrão diferente.
grafo com RefCell?
Possível para AST; considere arena se o desempenho for importante.
RefCell Send Sync?
RefCell não é Sync; não pode ser compartilhado entre threads em Arc sem Mutex.
clippy mutex?
Avisa sobre std::sync::Mutex em contextos async; use tokio::sync::Mutex.
testar pânico de borrow?
Use #[should_panic] em double borrow_mut em testes.
quando atomics são suficientes?
Contadores e flags sem proteger grandes structs.
Relacionado
Versões da Stack: Esta página foi escrita para Rust 1.97.0 (edição 2024), Tokio 1.x, Axum 0.8, serde 1.0, sqlx 0.8, clap 4, e Polars 0.46+.