构建FooBuilder
时,我想提供&mut Bar
。当我构建Foo
时,我想提供&Bar
,Foo
应该可以从&self
调用Bar
方法。换句话说,可变借用只应在FooBuilder
的生命期间存在。
struct FooBuilder<'a> {
bar: &'a mut Bar,
}
impl<'a> FooBuilder<'a> {
fn new(bar: &'a mut Bar) -> Self {
FooBuilder { bar: bar }
}
fn build(&'a self) -> Foo<'a> {
Foo { bar: &self.bar }
}
}
struct Foo<'a> {
bar: &'a Bar,
}
struct Bar;
impl Bar {
fn bar(&self) {}
}
fn main() {
let mut bar = Bar;
let foo = FooBuilder::new(&mut bar).build();
bar.bar();
}
此代码有错误:
error: borrowed value does not live long enough
--> <anon>:24:15
|
24 | let foo = FooBuilder::new(&mut bar).build();
| ^^^^^^^^^^^^^^^^^^^^^^^^^ does not live long enough
|
note: reference must be valid for the block suffix following statement 1 at 24:48...
--> <anon>:24:49
|
24 | let foo = FooBuilder::new(&mut bar).build();
| ^
note: ...but borrowed value is only valid for the statement at 24:4
--> <anon>:24:5
|
24 | let foo = FooBuilder::new(&mut bar).build();
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
help: consider using a `let` binding to increase its lifetime
--> <anon>:24:5
|
24 | let foo = FooBuilder::new(&mut bar).build();
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
error[E0502]: cannot borrow `bar` as immutable because it is also borrowed as mutable
--> <anon>:25:5
|
24 | let foo = FooBuilder::new(&mut bar).build();
| --- mutable borrow occurs here
25 | bar.bar();
| ^^^ immutable borrow occurs here
26 | }
| - mutable borrow ends here
error: aborting due to 2 previous errors
答案 0 :(得分:2)
第一步是修复build
。
为了将&mut T
转换为&T
,您需要使用 &mut T
(否则您会有别名和可变性)。这意味着:
简而言之,你来自:
fn build(&'a self) -> Foo<'a> {
Foo { bar: &self.bar }
}
为:
fn build(self) -> Foo<'a> {
Foo { bar: self.bar }
}
这会给您留下一个错误:
error: cannot borrow `bar` as immutable because it is also borrowed as mutable [--explain E0502]
--> <anon>:25:5
24 |> let foo = FooBuilder::new(&mut bar).build();
|> --- mutable borrow occurs here
25 |> bar.bar();
|> ^^^ immutable borrow occurs here
26 |> //foo.bar.bar();
27 |> }
|> - mutable borrow ends here
就编译器可以从方法签名中看到的那样,bar
是可变的,因此无法直接使用。借用延长直至foo
被删除。
此修复非常简单:不是直接使用bar
,而是使用bar
中的foo
引用。或者说明范围很重要:
fn main() {
let mut bar = Bar;
{
let foo = FooBuilder::new(&mut bar).build();
// `bar` currently borrow (mutably) by `foo`, cannot use it directly
foo.bar.bar();
}
// `bar` no longer borrowed, use at your heart's content
bar.bar();
}
答案 1 :(得分:1)
如果您不介意bar
Rc
,请执行类似的操作。诀窍是,如果只有一个Rc
引用,您可以获得对内容的&mut
引用。这有点倒退;它不是在编译时将&mut
降级为&
,而是利用运行时信息(引用计数)来升级&#34;从不可变的引用变为可变的。
use std::rc::Rc;
struct FooBuilder<'a> {
bar: &'a mut Rc<Bar>,
}
impl<'a> FooBuilder<'a> {
fn new(bar: &'a mut Rc<Bar>) -> Self {
FooBuilder { bar: bar }
}
fn f(mut self) -> Self {
Rc::get_mut(self.bar).unwrap().mut_method();
self
}
fn build(&'a self) -> Foo {
Foo { bar: self.bar.clone() }
}
}
struct Foo {
bar: Rc<Bar>,
}
struct Bar;
impl Bar {
fn bar(&self) {}
fn mut_method(&mut self) {}
}
fn main() {
let mut bar = Rc::new(Bar);
let foo = FooBuilder::new(&mut bar).f().build();
bar.bar();
}
使用Rc
克隆构建Foo后,会有多个引用,稍后尝试获取mut
引用会引起恐慌(或者至少返回None
Rc::get_mut()
)。
这意味着你只能这样做一次;如果您希望第二个FooBuilder
从同一个Foo
创建第二个bar
,那么它将无法正常工作,因为如果您有一个&mut T
,则不允许任何其他引用lapply
。
但这有点笨拙,根据具体情况,可能有更好的方法来解决实际问题。