2016-07-28 8 views
4

FooBuilderを作成する場合、&mut Barを提供します。私がFooをビルドするときに&BarFooを提供したいのであれば、&selfのメソッドをBarから起動できるはずです。換言すれば、変動可能な借り入れは、生涯にわたって存在しているのはFooBuilderである。ビルダーへの変更可能な参照を与えるにはどうすればよいのですか?

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

あなたの質問は何ですか? – antoyo

+3

質問を修正して既存の回答を無効にするのは、最高の礼儀ではありません。 – Shepmaster

+0

私はこれが可能だとは思わない、申し訳ありません。変更可能な参照を共有のものにダウングレードして、共有の有効期間を取り戻すことはできません。 – Veedrac

答えて

1

あなたはRcbarを包む気にしない場合は、似たような操作を行うことができます。

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(); 
} 

このコードは、エラーが発生しました。トリックには、Rcの参照が1つしかない場合は、その内容への参照を&mutにすることができます。これは後ろ向きです。コンパイル時に&mut&にダウングレードするのではなく、変更可能なリファレンスから不変リファレンスを "アップグレード"するためにランタイム情報(参照カウント)を使用しています。

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(); 
} 

Play link

fooはRcクローンを用いて構築された後、複数の基準とmut参照パニック(又は少なくともRc::get_mut()からNoneを返す)ことになるを取得するために後で試みがあります。

これは、これを1回だけ実行できることを意味します。もう1つのFooBuilderを作成する場合は、同じbarから2番目のFooを作成することはできません。&mut Tの場合、他の参照は許可されていません。

これは少し不器用ですが、実際の問題を解決する方法は状況によって異なります。

+1

あなたが動的にチェックしているなら、 'RefCell'ははるかにヘビー級です。 https://play.rust-lang.org/?gist=88a746b54a6cd6e6ede1818c8ce136d2&version=stable&backtrace=0 – Veedrac

+0

これは当てはまりますが、「不変に変換する」部分はありません。私はそれが必然的に必要だと言っているわけではありません! –

2

最初の手順は、buildを修正することです。あなたがに必要&T&mut 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がmutably借りているので、直接使用することはできません。借り入れはfooまで延期されます。

修正は非常に簡単です。barを直接使用する代わりに、fooの参照番号barを使用してください。または、範囲が重要であることを明確にする:

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

私はあなたがその質問を誤解していると思います。私の理解は、あなたの最後のステップである 'bar'を使う前に' foo'を捨てることが、OPの望みに反していることです。 OPは、 'foo'と' bar'を両方とも不変に一緒に使用できるようにしたい。 – Veedrac

+0

@Veedrac:それは私が質問から得たものではありませんが、今私はそれがこのようにも読むことができる方法を見ています。 OPがこの答えをどのように考えるか見てみましょう。 –

関連する問題