Mutabilidade Interior
Em algumas situações, é necessário modificar dados atrás de uma referência compartilhada (somente leitura). Por exemplo, uma estrutura de dados compartilhada pode ter um cache interno e desejar atualizar esse cache a partir de métodos somente leitura.
O padrão de “mutabilidade interna” permite acesso exclusivo (mutável) por trás de uma referência compartilhada. A biblioteca padrão fornece várias maneiras de fazer isso, garantindo segurança, geralmente realizando uma verificação em tempo de execução.
RefCell
use std::cell::RefCell; fn main() { // Observe que `cell` NÃO é declarado como mutável. let cell = RefCell::new(5); { let mut cell_ref = cell.borrow_mut(); *cell_ref = 123; // Isso gera um erro em tempo de execução. // let other = cell.borrow(); // println!("{}", *other); } println!("{cell:?}"); }
Cell
Cell envolve um valor e permite obter ou definir o valor, mesmo com uma referência compartilhada para o Cell. No entanto, não permite nenhuma referência ao valor. Como não há referências, as regras de empréstimo não podem ser quebradas.
use std::cell::Cell; fn main() { // Observe que `cell` NÃO é declarado como mutável. let cell = Cell::new(5); cell.set(123); println!("{}", cell.get()); }
O principal a ser observado neste slide é que o Rust fornece maneiras seguras de modificar dados por trás de uma referência compartilhada. Há uma variedade de maneiras de garantir essa segurança, e RefCell e Cell são duas delas.
-
RefCellfaz cumprir as regras de empréstimo usuais do Rust (ou várias referências compartilhadas ou uma única referência exclusiva) com uma verificação em tempo de execução. Neste caso, todos os empréstimos são muito curtos e nunca se sobrepõem, então as verificações sempre têm sucesso.- O bloco extra no exemplo de
RefCellé para encerrar o empréstimo criado pela chamada aborrow_mutantes de imprimir ocell. Tentar imprimir umRefCellemprestado mostra apenas a mensagem"{borrowed}".
- O bloco extra no exemplo de
-
Cellé um meio mais simples de garantir a segurança: ele tem um métodosetque recebe&self. Isso não precisa de uma verificação em tempo de execução, mas requer mover valores, o que pode ter seu próprio custo. -
Tanto
RefCellquantoCellsão!Sync, o que significa que&RefCelle&Cellnão podem ser passados entre threads. Isso impede que duas threads tentem acessar ocellao mesmo tempo.