实施“谨慎”的take_while使用Peekable [英] Implementing a "cautious" take_while using Peekable

查看:221
本文介绍了实施“谨慎”的take_while使用Peekable的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我想使用 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!='。');

//屈服(abc =abc,defg =defg)

我在在这里创建了一个MCVE 上采访了一下,但我得到了:


:10:5:10:19错误:无法摆脱借来的内容
: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是针对Iterator 类型的可变指针实现的。聪明!

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

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



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



解决方案,不要带 Peekable< T> 但是& mut Peekable< ; T> 。您还需要指定生命周期:

  impl<'a,T:Iterator,P> CautiousTakeWhile的迭代器<&'mut Peekable< T>,P> 
其中P:FnMut(& T :: Item) - > bool {
// ...
}

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

此解决方案的一个奇怪的副作用是现在不需要 by_ref ,因为 cautious_take_while()采用可变参考,因此它不会窃取所有权。 take_while()需要 by_ref()调用,因为它可以采用 Peekable< T> & mut Peekable< T> ,默认为第一个。使用 by_ref()调用它将解析为第二个。



现在我终于明白了,我认为改变 struct CautiousTakeWhile 将可窥探的位包含在结构本身中。困难在于,如果我是对的,必须手动指定寿命。类似于:

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

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


I'd like to use Peekable as the basis for a new cautious_take_while operation that acts like take_while from IteratorExt but without consuming the first failed item. (There's a side question of whether this is a good idea, and whether there are better ways to accomplish this goal in Rust -- I'd be happy for hints in that direction, but mostly I'm trying to understand where my code is breaking).

The API I'm trying to enable is basically:

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")

I've taken a crack at creating a MCVE here, but I'm getting:

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

As far as I can tell, I'm following the same pattern as Rust's own TakeWhile in terms of my function signatures, but I'm seeing different different behavior from the borrow checker. Can someone point out what I'm doing wrong?

解决方案

The funny thing with by_ref() is that it returns a mutable reference to itself:

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

It works because the Iterator trait is implemented for the mutable pointer to Iterator type. Smart!

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

The standard take_while function works because it uses the trait Iterator, that is automatically resolved to &mut Peekable<T>.

But your code does not work because Peekable is a struct, not a trait, so your CautiousTakeWhileable must specify the type, and you are trying to take ownership of it, but you cannot, because you have a mutable pointer.

Solution, do not take a Peekable<T> but &mut Peekable<T>. You will need to specify the lifetime too:

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

A curious side effect of this solution is that now by_ref is not needed, because cautious_take_while() takes a mutable reference, so it does not steal ownership. The by_ref() call is needed for take_while() because it can take either Peekable<T> or &mut Peekable<T>, and it defaults to the first one. With the by_ref() call it will resolve to the second one.

And now that I finally understand it, I think it might be a good idea to change the definition of struct CautiousTakeWhile to include the peekable bit into the struct itself. The difficulty is that the lifetime has to be specified manually, if I'm right. Something like:

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;
}

and the rest is more or less straightforward.

这篇关于实施“谨慎”的take_while使用Peekable的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆