2016-05-29 2 views
0
use std::iter::Peekable; 

pub trait AdvanceWhile<I: Iterator> { 
    fn advance_while<P>(&mut self, predicate: P) 
    where 
     P: Fn(&I::Item) -> bool; 
} 

impl<I: Iterator> AdvanceWhile<I> for Peekable<I> { 
    fn advance_while<P>(&mut self, predicate: P) 
    where 
     P: Fn(&I::Item) -> bool, 
    { 
     while let Some(val) = self.peek() { 
      if predicate(val) { 
       self.next(); 
      } else { 
       break; 
      } 
     } 
    } 
} 

PlaygroundPeekable :: peekの結果に基づいてPeekable :: nextを呼び出すにはどうすればよいですか?

エラー:字句借入の

error[E0499]: cannot borrow `*self` as mutable more than once at a time 
    --> src/main.rs:16:17 
    | 
14 |   while let Some(val) = self.peek() { 
    |        ---- first mutable borrow occurs here 
15 |    if predicate(val) { 
16 |     self.next(); 
    |     ^^^^ second mutable borrow occurs here 
... 
20 |   } 
    |   - first borrow ends here 
+0

この[にクロス投稿されましたユーザーフォーラム](https://users.rust-lang.org/t/how-do-i-work-with-the-borrow-checker-in-this-case/6005?u=shepmaster)を参照してください。 – Shepmaster

答えて

1

Lukas Kalbertodtように、これは借りチェッカーの制限です。ここで私はより読みやすいバージョンを表示したいと思います:

fn advance_while<P>(&mut self, predicate: P) 
    where P: Fn(&I::Item) -> bool 
{ 
    while let Some(true) = self.peek().map(&predicate) { 
     self.next(); 
    } 
} 
2

典型的なケース:コンパイラは、まだこのコードが安全であるであることを理解することはできません。だから当分の間(いわゆる非語彙借用が実装されるまで)、あなたのコードを書き直してみてください。このように、例えば:

fn advance_while<P>(&mut self, predicate: P) 
    where P: Fn(&I::Item) -> bool 
{ 
    loop { 
     if let Some(val) = self.peek() { 
      if !predicate(val) { 
       break; 
      } 
     } else { 
      break; 
     } 
     self.next(); 
    } 
} 
1

あなたはこのに関数を書き換えることができます:既に述べ

impl<I: Iterator> AdvanceWhile<I> for Peekable<I> { 
    fn advance_while<P>(&mut self, predicate: P) 
     where P: Fn(&I::Item) -> bool 
    { 
     loop { 
      { 
       let peek = match self.peek() { 
        Some(p) => p, 
        None => break, 
       }; 
       if !predicate(peek) { 
        break; 
       } 
      } 
      self.next(); 
     } 
    } 
} 
0

わかりましたので、これはそれを行うための最善の方法ではありませんが、それは、より複雑な場合のために便利になるかもしれません...

fn advance_while<P>(&mut self, predicate: P) 
    where P: Fn(&I::Item) -> bool 
{ 
    while { 
     if let Some(val) = self.peek() { 
      predicate(val) 
     } else { 
      false 
     } 
    } 
    { 
     self.next(); 
    } 
} 

Playpen

1

問題は、元のコードはこれを行うことができることである:

while let Some(val) = self.peek() { 
    if predicate(val) { 
     self.next(); 
     println!("{:?}", val); 
    } else { 
     break; 
    } 
} 

next()を呼び出した後にvalにアクセスすると、もはや有効ではなかったメモリにアクセスでき、メモリが不安定になります。

他の人が指摘したように、あなたのコードが実際にはこれを行わないんが、現在の錆は字句寿命、参照のために有効にする必要がどのくらいの過度-保守的な近似を使用しています。未来の錆は安全でないことを導入することなく論理を拘束するのに役立つはずです。


あなたの値はCopyを実装している場合、あなたはそれを利用することができます:

fn advance_while<P>(&mut self, predicate: P) 
where 
    P: Fn(&I::Item) -> bool, 
    I::Item: Copy, 
{ 
    while let Some(&val) = self.peek() { 
     if predicate(&val) { 
      self.next(); 
     } else { 
      break; 
     } 
    } 
} 

これは、値はpeekによって返された参照からコピーされます。何も借用されていないので、イテレータを変更しようとしているという事実は問題にはなりません。

あなたのタイプはCloneを実装している場合、あなたは再びそれを解離、値のクローンを作成できます。

fn advance_while<P>(&mut self, predicate: P) 
where 
    P: Fn(&I::Item) -> bool, 
    I::Item: Clone, 
{ 
    while let Some(val) = self.peek().cloned() { 
     if predicate(&val) { 
      self.next(); 
     } else { 
      break; 
     } 
    } 
} 

あなたのタイプはCopyCloneでもない場合は、boolean型の結果のために一時的な変数を導入する必要があります。これは明らかにpeekによって返さボローが平等チェック声明を超えて必要とされていないコンパイラに通知:

fn advance_while<P>(&mut self, predicate: P) 
where 
    P: Fn(&I::Item) -> bool, 
{ 
    while self.peek().map_or(false, &predicate) { 
     self.next(); 
    } 
} 

も参照してください:

関連する問題