RAII & Drop Guards
Aquisição de Recursos é Inicialização (RAII): adquira recursos em construtores, libere em Drop quando o escopo terminar. Guards de escopo executam a limpeza mesmo em pânico (com unwinding).
Receita
struct TempDirGuard(tempfile::TempDir);
impl Drop for TempDirGuard {
fn drop(&mut self) { /* tempdir é deletado no drop */ }
}Quando usar isso: Locks, arquivos, transações, timers de métricas, restauração de estado anterior.
Exemplo Funcional
struct ResetFlag<'a> { flag: &'a AtomicBool, prev: bool }
impl<'a> ResetFlag<'a> {
fn guard(flag: &'a AtomicBool, value: bool) -> Self {
let prev = flag.swap(value, Ordering::SeqCst);
ResetFlag { flag, prev }
}
}
impl Drop for ResetFlag<'_> {
fn drop(&mut self) {
self.flag.store(self.prev, Ordering::SeqCst);
}
}
fn work() {
let _g = ResetFlag::guard(&IN_PROGRESS, true);
// flag é restaurado quando _g sai do escopo
}O que isso demonstra:
- O binding
_gmantém o guard vivo até o fim do escopo Dropé executado em retornos normais e em pânico (unwinding)- Encapsula a lógica de restauração em um só lugar
- Crate
scopeguardpara guards baseados em closures
Mergulho Profundo
Padrão defer com scopeguard::guard((), |_| cleanup()). Guards de Mutex (MutexGuard) são locks RAII. Tarefas tokio::spawn devem usar RAII para contadores em andamento.
Armadilhas
- Ordem de
Drop- campos são liberados na ordem inversa de declaração. Correção: estruture os campos se a ordem importar. panic=abort- semdropde unwinding em algumas compilações. Correção: limpeza crítica pode precisar de caminhos explícitos estilofinallytambém para compilações com abort.Dropassíncrono - não é automático. Correção: futuro de shutdown explícito ouDropapenas para recursos síncronos.- Binding
_esquecido - guard é liberado imediatamente. Correção:let _guard = ...para escopo completo. - Deadlock no
drop- ordem de lock em guards aninhados. Correção: ordenação consistente de locks.
Alternativas
| Alternativa | Usar Quando | Não Usar Quando |
|---|---|---|
try/finally manual | caminho crítico de compilações com abort | RAII Rust normal |
crate scopeguard | Guard de closure rápido | Tipo customizado mais claro |
close() explícito | Shutdown assíncrono | Handles de arquivo síncronos |
FAQs
Drop em pânico?
Sim, com unwinding; use catch_unwind na fronteira se necessário.
Dropar manualmente cedo?
drop(guard) antes do fim do escopo.
Drop e Cópia?
Tipos de cópia podem implementar Drop com cuidado; padrão raro.
Ordem de campos de Drop em union?
Use guards aninhados ou uma única struct que possua múltiplos recursos.
Log em Drop?
Evite logs em Drop que pode entrar em pânico; mantenha Drop infalível.
Rollback de transação?
Guard de transação de DB faz rollback a menos que seja commitado.
Timer de métricas guard?
Registra a duração no Drop da struct do timer.
Esquecer guard?
mem::forget vaza o recurso intencionalmente; documente o porquê.
Guard Send/Sync?
Campos do guard determinam auto traits; cuidado com RefCell no guard.
Testar Drop?
Use flags atômicas ou contadores verificados após o escopo.
Relacionados
- Noções Básicas de Ponteiros Inteligentes - trait Drop
- Mutex e RwLock - guards de lock
- Anti-Padrões Comuns - padrões de vazamento
- 30 Regras Unsafe
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+.