使用Peekable实现"谨慎"的take_while

Bos*_*osh 5 iterator traits rust borrow-checker

我想使用Peekable作为一个新的基础cautious_take_while,其作用类似于操作 take_while距离IteratorExt,但不消耗第一个失败的项目.(还有一个问题是这是否是一个好主意,以及是否有更好的方法来实现Rust的这一目标 - 我很乐意在这个方向上提示,但主要是我试图了解我的代码在哪里断).

我试图启用的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")
Run Code Online (Sandbox Code Playgroud)

我在这里创造了一个MCVE,但是我得到了:

:10:5:10:19错误:无法移出借来的内容:10 chars.by_ref().cautious_take_while(|&x | x!='.');

据我所知,TakeWhile在我的函数签名方面,我遵循与Rust自己相同的模式,但我看到了与借用检查器不同的不同行为.有人可以指出我做错了吗?

rod*_*igo 5

有趣的by_ref()是它返回一个对自身的可变引用:

pub trait IteratorExt: Iterator + Sized {
    fn by_ref(&mut self) -> &mut Self { self }
}
Run Code Online (Sandbox Code Playgroud)

它的工作原理是因为为Iterator类型Iterator可变指针实现了特性.聪明!

impl<'a, I> Iterator for &'a mut I where I: Iterator, I: ?Sized { ... }
Run Code Online (Sandbox Code Playgroud)

标准take_while函数有效,因为它使用了Iterator自动解析的特征&mut Peekable<T>.

但是你的代码不起作用,因为它Peekable是一个结构,而不是一个特征,所以你CautiousTakeWhileable必须指定类型,并且你试图取得它的所有权,但你不能,因为你有一个可变的指针.

解决方案,不要拿一个Peekable<T>但是&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,}
    }
}
Run Code Online (Sandbox Code Playgroud)

这个解决方案的一个奇怪的副作用是现在by_ref不需要,因为cautious_take_while()需要一个可变的引用,所以它不会窃取所有权.在by_ref()需要用于呼叫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;
}
Run Code Online (Sandbox Code Playgroud)

其余的或多或少是直截了当的.