Qual é a maneira correta de implementar o equivalente a vários retornos de chamada mutáveis (alocados estaticamente, despachados estaticamente etc.) no Rust?
Eu tenho o seguinte código de exemplo, que é a base padrão de APIs orientadas a eventos em outras linguagens de programação, mas no Rust o verificador de empréstimo o bloqueia com "não é possível emprestarp1
mutável mais de uma vez de cada vez ":
struct Pen {
color_cmyk: u32,
ink: usize,
}
impl Pen {
pub fn new() -> Pen {
Pen {
color_cmyk: 0x80800000,
ink: 20000,
}
}
pub fn write(&mut self, text: &str) -> bool {
if self.ink < text.len() {
return false;
}
self.ink -= text.len();
true
}
}
fn main() {
println!("Hello, world !");
let mut p1 = Pen::new();
p1.write("Hello");
println!("ink: {}, color: {}", p1.ink, p1.color_cmyk);
let mut cb = |text| if p1.write(text) {
println!("{}", text);
} else {
println!("Out of ink !");
};
let mut cb2 = |text| {
p1.write(text);
p1.ink
};
cb("Hello");
cb("World");
println!("{}", cb2("Hello"));
}
error[E0499]: cannot borrow `p1` as mutable more than once at a time
--> src/main.rs:37:23
|
31 | let mut cb = |text| if p1.write(text) {
| ------ -- previous borrow occurs due to use of `p1` in closure
| |
| first mutable borrow occurs here
...
37 | let mut cb2 = |text| {
| ^^^^^^ second mutable borrow occurs here
38 | p1.write(text);
| -- borrow occurs due to use of `p1` in closure
...
45 | }
| - first borrow ends here
O código pode ser usado, por exemplo, para implementar dois retornos de chamada em uma janela: um para manipular eventos de teclado e outro para manipular eventos de mouse, os quais atualizam o estado da janela (por exemplo: alteração de cor, fechamento da janela etc.).
Sei que essa pergunta aparece em outro lugar no Stack Overflow e em outros fóruns, mas, em geral, as respostas se concentram na descrição do motivo do problema e raramente propõem uma solução geral completa para ele:
Não é possível emprestar o `x` como mutável mais de uma vez por vezComo ignorar "não pode emprestar como mutável mais de uma vez"?Não é possível emprestar como mutável mais de uma vez por vezPassando o contexto mutável para retornos de chamadaCriando um sistema de retorno de chamada usando fechamentosExecutar retornos de chamada como empréstimos mutáveis do cicloRetorno de chamada para auto mutável