Ambiente : rustc 1.82.0 (f6e511eec 2024-10-15)
Pergunta: Desreferenciamento vs. Empréstimo Direto em Rust
Estou confuso sobre a diferença entre *&T
e T
em empréstimo. O código a seguir compila com let b = &mut *a
, mas falha com let b = &mut x
. Por que *a
se comporta diferentemente de x
neste contexto?
Além disso, descomentar a última linha ( *b = ...
) causa o erro:
não pode atribuir
*a
porque é emprestado
fn annoying_borrow() {
let mut x = Box::new(1);
let a = &mut x;
let b = &mut *a;
// let b = &mut x; // error: cannot borrow `x` as mutable more than once at a time
*a = Box::new(2);
// *b = Box::new(3); // error: `*a` is assigned to here but it was already borrowed
}
Usar the *a
em vez de the x
here implica ainda mais na sutil diferença entre eles? Emmm, o que eu realmente quero explorar não é a diferença entre *a
and x
, mas as regras de empréstimo no sistema de tipos Rust (compilador).
Fundo:
Consultei Programming Rust, 2ª edição (Capítulo 5), mas não consigo compreender totalmente esse conhecimento:
O acesso compartilhado é somente leitura.
Valores emprestados por referências compartilhadas são somente leitura. Ao longo da vida útil de uma referência compartilhada, nem seu referente, nem nada alcançável daquele referente, pode ser alterado por nada. Não existem referências mutáveis vivas para nada naquela estrutura, seu proprietário é mantido somente leitura, e assim por diante. Está realmente congelado.
Acesso mutável é acesso exclusivo.
Um valor emprestado por uma referência mutável é alcançável exclusivamente por meio dessa referência. Ao longo do tempo de vida de uma referência mutável, não há outro caminho utilizável para seu referente ou para qualquer valor alcançável a partir daí. As únicas referências cujos tempos de vida podem se sobrepor a uma referência mutável são aquelas que você pega emprestado da própria referência mutável.
Gostaria de saber se há alguma explicação unificada e detalhada sobre empréstimos em Rust. Talvez houvesse um conjunto claro de regras sobre empréstimos em Rust, mas com o compilador relaxando continuamente as restrições de sintaxe (para facilitar a codificação em certos cenários?), as regras atuais são mais caóticas?
Referências mutáveis podem ser 'inativas'. Apenas uma referência mutável pode estar ativamente mantendo acesso mutável exclusivo, mas só porque uma referência existe, não significa que ela mantém acesso. Quando você toma emprestado por meio de uma referência mutável, esse acesso é transferido para a referência que toma emprestado.
Isso significa que você pode criar uma referência mutável b por meio da referência mutável a que tem acesso, transferindo o acesso de a para b, até que b seja descartado quando ele for revertido para a. Você não pode usar a diretamente enquanto b existir, porque ele não tem acesso, assim como x não tem acesso enquanto a existir.
Além disso, você pode criar uma referência compartilhada a partir de uma referência mutável. Nesse caso, o acesso às referências mutáveis é rebaixado para compartilhado até que a última referência emprestada seja descartada.