iterator - 使用 Peekable 实现 "cautious"take_while

标签 iterator rust traits 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")

我已经破解了 creating a MCVE here ,但我得到:

:10:5: 10:19 error: cannot move out of borrowed content :10 chars.by_ref().cautious_take_while(|&x| x != '.');

据我所知,我正在遵循与 Rust 自己的 TakeWhile 相同的模式就我的函数签名而言,但我从借用检查器中看到了不同的行为。有人可以指出我做错了什么吗?

最佳答案

关于 by_ref() 的有趣之处是它返回对自身的可变引用:

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

之所以有效,是因为 Iterator trait 是为指向迭代器的可变指针 类型实现的。聪明!

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

标准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,}
    }
}

这个解决方案的一个奇怪的副作用是现在 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;
}

剩下的就比较简单了。

关于iterator - 使用 Peekable 实现 "cautious"take_while,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/28776630/

相关文章:

java - 实现迭代器时索引不递增

c++ - 如何从传递给某些 STL 算法的谓词中获取元素索引?

java - 在java中加入多个迭代器

Rust 对特征实现的自动类型推断

rust - Rust 可以自动获取值的不可变引用吗?

rust - 使用 Glium 进行高效的 2D 渲染

rust - 防止值在通用匹配中掉落

具有 "simple"和 "advanced"版本的 Rust 特征

iterator - "Sized is not implemented for the type str"与字符串文字匹配时?

rust - 如何告诉Rust我的自定义特征已经实现了 `num_traits::pow::Pow`函数