У меня есть код, который работает, но он перестает компилироваться с ошибкой проверки заимствования после изменения. Я не понимаю, как изменение может повлиять на проверку заимствований.
Общая часть как рабочего, так и нерабочего кода:
/// Some struct that has references inside
#[derive(Debug)]
struct MyValue<'a> {
number: &'a u32,
}
/// There are many structs similar to `MyValue` and there is a
/// trait common to them all that can create them. In this
/// example I use the `From` trait.
impl<'a> From<&'a u32> for MyValue<'a> {
fn from(value: &'a u32) -> Self {
MyValue { number: value }
}
}
/// `Producer` makes objects that hold references into it. So
/// the produced object must be first dropped before any new
/// one can be made.
trait Producer<'a, T: 'a> {
fn make(&'a mut self) -> T;
}
Вот рабочий код:
struct MyProducer {
number: u32,
}
impl MyProducer {
fn new() -> Self {
Self { number: 0 }
}
}
impl<'a, T: 'a + From<&'a u32>> Producer<'a, T> for MyProducer {
fn make(&'a mut self) -> T {
self.number += 1;
T::from(&self.number)
}
}
fn main() {
let mut producer = MyProducer::new();
println!(
"made this: {:?}",
<MyProducer as Producer<MyValue>>::make(&mut producer)
);
println!(
"made this: {:?}",
<MyProducer as Producer<MyValue>>::make(&mut producer)
);
}
Компилирует и печатает ожидаемый результат:
made this: MyValue { number: 1 }
made this: MyValue { number: 2 }
Мне не нравится, что MyProducer
фактически реализует Producer
для каждого T
, так как это делает невозможным непосредственный вызов make
для него. Я хотел бы иметь тип, который является MyProducer
для определенного T
(например, для MyValue
).
Для этого я хочу добавить универсальный параметр в MyProducer
. Поскольку MyProducer
на самом деле не использует T
, я использую PhantomData
, чтобы компилятор не жаловался.
Вот код после изменений:
use std::marker::PhantomData;
struct MyProducer<'a, T: 'a + From<&'a u32>> {
number: u32,
_phantom: PhantomData<&'a T>,
}
impl<'a, T: 'a + From<&'a u32>> MyProducer<'a, T> {
fn new() -> Self {
Self {
number: 0,
_phantom: PhantomData::default(),
}
}
}
impl<'a, T: From<&'a u32>> Producer<'a, T> for MyProducer<'a, T> {
fn make(&'a mut self) -> T {
self.number += 1;
T::from(&self.number)
}
}
fn main() {
let mut producer = MyProducer::<MyValue>::new();
println!("made this: {:?}", producer.make());
println!("made this: {:?}", producer.make());
}
Функция main
теперь выглядит именно так, как мне хотелось бы, чтобы она выглядела. Но код не компилируется. Это ошибка:
error[E0499]: cannot borrow `producer` as mutable more than once at a time
--> src/main.rs:50:33
|
49 | println!("made this: {:?}", producer.make());
| -------- first mutable borrow occurs here
50 | println!("made this: {:?}", producer.make());
| ^^^^^^^^
| |
| second mutable borrow occurs here
| first borrow later used here
Я не понимаю, почему это больше не работает. Произведенный объект по-прежнему сбрасывается до создания следующего.
Если я вызываю функцию make
только один раз, она компилируется и работает.
Я использую редакцию 2018, поэтому NLL активен.
Rust Playground: рабочая версия до изменения
Rust Playground: сломанная версия после изменения