5

fromのように動作するが、最初に失敗したアイテムを消費しない新しい操作 Peekableの基礎として使用したいと思います。(これが良いアイデアかどうか、Rust でこの目標を達成するためのより良い方法があるかどうかという副次的な質問があります。その方向のヒントがあれば幸いですが、ほとんどの場合、自分のコードがどこにあるかを理解しようとしています。速報)。cautious_take_whiletake_whileIteratorExt

有効にしようとしている API は基本的に次のとおりです。

let mut chars = "abcdefg.".chars().peekable();

let abc : String = chars.by_ref().cautious_take_while(|&x| x != 'd');
let defg : String = chars.by_ref().cautious_take_while(|&x| x != '.');

// yielding (abc = "abc", defg = "defg")

ここで MCVEを作成してみましたが、次のようになりました。

:10:5: 10:19 エラー: 借用したコンテンツから移動できません:10 chars.by_ref().cautious_take_while(|&x| x != '.');

私が知る限りTakeWhile、関数シグネチャに関して Rust のものと同じパターンに従っていますが、借用チェッカーとは異なる動作が見られます。誰かが私が間違っていることを指摘できますか?

4

2 に答える 2

5

の面白い点by_ref()は、それ自体への変更可能な参照を返すことです。

pub trait IteratorExt: Iterator + Sized {
    fn by_ref(&mut self) -> &mut Self { self }
}

これは、Iterator型へのミュータブル ポインターIteratorに対してトレイトが実装されているため機能します。頭いい!

impl<'a, I> Iterator for &'a mut I where I: Iterator, I: ?Sized { ... }

標準関数は、自動的に に解決されるtake_whiletrait を使用するため機能します。Iterator&mut Peekable<T>

しかしPeekable、特性ではなく構造体であるため、コードは機能しません。そのためCautiousTakeWhileable、型を指定する必要があり、その所有権を取得しようとしていますが、変更可能なポインターがあるため、できません。

Peekable<T>解決策、 butは使用しないでください&mut Peekable<T>。ライフタイムも指定する必要があります。

impl <'a, T: Iterator, P> Iterator for CautiousTakeWhile<&'a mut Peekable<T>, P>
where P: FnMut(&T::Item) -> bool {
     //...
}

impl <'a, T: Iterator> CautiousTakeWhileable for &'a mut Peekable<T> {
    fn cautious_take_while<P>(self, f: P) -> CautiousTakeWhile<&'a mut Peekable<T>, P>
     where P: FnMut(&T::Item) -> bool {
        CautiousTakeWhile{inner: self, condition: f,}
    }
}

このソリューションの奇妙な副作用は、変更可能な参照を使用するため、所有権を盗まないby_refため、現在は必要ないということです。cautious_take_while()またはのいずれかを取ることができ、デフォルトで最初のものになるためby_ref()、呼び出しが必要です。呼び出しにより、2 番目のものに解決されます。take_while()Peekable<T>&mut Peekable<T>by_ref()

そして、ようやく理解できたので、 の定義を変更struct CautiousTakeWhileして、構造体自体にピーク可能なビットを含めることをお勧めします。難点は、私が正しければ、寿命を手動で指定する必要があることです。何かのようなもの:

struct CautiousTakeWhile<'a, T: Iterator + 'a, P> 
    where T::Item : 'a {
    inner: &'a mut Peekable<T>,
    condition: P,
}
trait CautiousTakeWhileable<'a, T>: Iterator {
    fn cautious_take_while<P>(self, P) -> CautiousTakeWhile<'a, T, P> where
        P: FnMut(&Self::Item) -> bool;
}

残りは多かれ少なかれ簡単です。

于 2015-02-28T01:53:53.270 に答える
1

これはトリッキーでした!コードの要点を説明してから、説明を試みます (理解できれば...)。付随的な複雑さを減らしたかったので、それは醜い無糖バージョンでもあります.

use std::iter::Peekable;

fn main() {
    let mut chars = "abcdefg.".chars().peekable();

    let abc: String = CautiousTakeWhile{inner: chars.by_ref(), condition: |&x| x != 'd'}.collect();
    let defg: String = CautiousTakeWhile{inner: chars.by_ref(), condition: |&x| x != '.'}.collect();
    println!("{}, {}", abc, defg);
}

struct CautiousTakeWhile<'a, I, P> //'
    where I::Item: 'a, //'
          I: Iterator + 'a, //'
          P: FnMut(&I::Item) -> bool,
{
    inner: &'a mut Peekable<I>, //'
    condition: P,
}

impl<'a, I, P> Iterator for CautiousTakeWhile<'a, I, P>
    where I::Item: 'a, //'
          I: Iterator + 'a, //'
          P: FnMut(&I::Item) -> bool
{
    type Item = I::Item;

    fn next(&mut self) -> Option<I::Item> {
        let return_next =
            match self.inner.peek() {
                Some(ref v) => (self.condition)(v),
                _ => false,
            };
        if return_next { self.inner.next() } else { None }
    }
}

実際、Rodrigo は適切な説明をしているようですので、具体的な説明を求められない限り、それに従います。

于 2015-02-28T01:52:54.973 に答える