2015-10-01 12 views
6

エンティティシステム用のコードをゲームに書き込もうとしていますが、このエラーが発生しているので、同じことをするコードに煮詰めました。実際のコードでは同じエラーです。構造メソッドの借用エラーについて混乱しました

bazが終了したときに、self.my_listへの参照が範囲外になることをコンパイラーが私に伝えている理由を理解できません。

私の錆のバージョンは、私はforループが終了したとき、それはスコープの外に出ることを考えているだろうrustc 1.3.0 (9a92aaf19 2015-09-15)

のですか?

struct Foo { 
    name : &'static str, 
} 

struct Bar { 
    my_list : Vec<Foo>, 
} 

impl Bar { 
    fn New() -> Bar { 
     let mut new_instance = Bar { my_list : vec!() }; 
     new_instance.my_list.push(Foo { name : "foo1" }); 
     new_instance.my_list.push(Foo { name : "foo2" }); 
     new_instance.my_list.push(Foo { name : "foo3" }); 
     return new_instance; 
    } 

    fn Baz(&mut self, name : &'static str) -> Option<&Foo> { 
     for x in &self.my_list { 
      if x.name == name { 
       return Some(x); 
      } 
     } 

     self.my_list.push(Foo { name : "foo" }); 

     return None; 
    } 
} 

fn main() { 
    let mut bar = Bar::New(); 
    if let Some(x) = bar.Baz("foo1") { 
     println!("{} found", x.name); 
    } 
} 

これは私が取得エラーメッセージです:これは借りチェッカーの制限です

Compiling tutorial v0.1.0 (file:///C:/Code/Projects/rust/tutorial) 
src\main.rs:35:9: 35:21 error: cannot borrow `self.my_list` as mutable because it is also borrowed as immutable 
src\main.rs:35   self.my_list.push(Foo { name : "foo" }); 
         ^~~~~~~~~~~~ 
src\main.rs:29:19: 29:31 note: previous borrow of `self.my_list` occurs here; the immutable borrow prevents subsequent moves or mutable borrows of `self.my_list` until the borrow ends 
src\main.rs:29   for x in &self.my_list { 
           ^~~~~~~~~~~~ 
note: in expansion of for loop expansion 
src\main.rs:29:9: 33:10 note: expansion site 
src\main.rs:38:6: 38:6 note: previous borrow ends here 
src\main.rs:28  fn Baz(&mut self, name : &'static str) -> Option<&Foo> { 
... 
src\main.rs:38  } 
       ^
error: aborting due to previous error 
Could not compile `tutorial`. 

To learn more, run the command again with --verbose. 
+0

は... –

+2

これは場合にのみ発生しますfor-loopで参照を返します。問題のMCVEはここにあります:http://is.gd/dJFkUz –

+2

[desugared版](http://is.gd/atsegO)にも同じ問題があります。これは確かにバグのような気分です... – Shepmaster

答えて

1

。関数が安全であると推論する方法は、関数を本質的に2つのパスとして扱います。関数がSome(x)を返すパスに沿って、my_listを再度借りないで、関数がNoneを返すパスに沿って、 forループの後。

これは、借用チェッカーが関数を調べる方法ではありません。借用チェッカーは語彙の範囲で動作します。可能な限り狭いスコープを選択しようとしますが、必要に応じてそのスコープ全体の機能をスコープとして扱います。戻り値の有効期間は、有効期間がselfと同じであることが分かります。したがって、xで参照される値の有効期間はselfと同じである必要があります。したがって、&self.my_listの借用期間はselfと同じでなければなりません。機能の復帰を超えてあなたは違った機能を記述する場合

、錆はそれを受け入れます:あなたは、同じエラーが発生した独自のスコープの中にループのために入れていても...奇妙だ

fn Baz(&mut self, name : &'static str) -> Option<&Foo> { 
    match self.my_list.iter().position(|x| x.name == name) { 
     Some(i) => Some(&self.my_list[i]), 
     None => { 
      self.my_list.push(Foo { name : "foo" }); 
      None 
     } 
    } 
} 
+0

で修正される可能性が最も高いです*この場合はボロウチェッカーはレキシカルスコープで動作します*別のレキシカルスコープは役に立ちません。 [desugared版](http://is.gd/atsegO)または[sugared版](http://is.gd/EHmRrU)は両方とも助けにならない字句的な範囲を持っています。 – Shepmaster

+0

私は明確にしようとしました。変数のスコープは重要ではありません。問題は、借用の範囲であり、直接的なレキシカルスコープを超えて拡張することができます。 –

関連する問題