我有可用的代码,但更改后它停止编译并出现借用检查器错误。我不知道该更改如何影响借入检查。
工作代码和非工作代码的共同部分:
/// 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处于 Activity 状态。
Rust Playground: working version before change
Rust Playground: broken version after change
最佳答案
我减少了代码中的噪音,因此以下是残破情况的更短版本,它演示了相同的问题:(test in the playground)
use std::marker::PhantomData;
#[derive(Debug)]
struct MyValue<'a>(&'a u32);
impl<'a> From<&'a u32> for MyValue<'a> {
fn from(value: &'a u32) -> Self {
MyValue(value)
}
}
struct MyProducer<'a, T>(u32, PhantomData<&'a T>);
impl<'a, T> MyProducer<'a, T>
where
T: From<&'a u32>,
{
fn new() -> Self {
Self(0, PhantomData)
}
fn make(&'a mut self) -> T {
self.0 += 1;
T::from(&self.0)
}
}
fn main() {
let mut producer = MyProducer::<MyValue>::new();
println!("made this: {:?}", producer.make());
println!("made this: {:?}", producer.make());
}
这里的主要问题是,可变借项的生存期是
MyProducer
的生存期,即,称为producer
的实例的生存期与其在make
方法中采取的可变借项相同。因为producer
实例不会超出范围(如果这样,则MyValue
将无法保存对存储在其中的值的引用),因此可变借项将一直存在到main
范围的末尾。借用的第一个规则是,在任何时候范围中只能有一个给定值的可变变量借用,因此会产生编译器错误。如果您在这里查看我的解决方案,该解决方案实际上正在工作,并且按照我认为您想要的去做:
#[derive(Debug)]
struct MyValue<'a>(&'a u32);
impl<'a> From<&'a u32> for MyValue<'a> {
fn from(value: &'a u32) -> Self {
MyValue(value)
}
}
struct MyProducer(u32);
impl MyProducer {
fn new() -> Self {
Self(0)
}
fn make<'a, T>(&'a mut self) -> T
where
T: From<&'a u32>,
{
self.0 += 1;
T::from(&self.0)
}
}
fn main() {
let mut producer = MyProducer::new();
println!("made this: {:?}", producer.make::<MyValue>());
println!("made this: {:?}", producer.make::<MyValue>());
}
然后您会看到可变借项的生存期限仅与
make
方法一样长,因此在调用之后,在producer
范围内不再有任何对main
的 Activity 可变借项,因此您可以拥有另一个。关于rust - 向结构添加通用参数后出现借入检查器错误,我们在Stack Overflow上找到一个类似的问题:https://stackoverflow.com/questions/56058392/