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

问题描述

我想使用 Peekable 作为新 cautious_take_while 操作的基础,该操作类似于 IteratorExt 中的 take_whilecode> 但不消耗第一个失败的项目.(还有一个问题是这是否是一个好主意,以及是否有更好的方法来在 Rust 中实现这个目标——我很乐意得到这个方向的提示,但主要是我试图理解我的代码在哪里打破).

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

我尝试启用的 API 基本上是:

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

我已经尝试在这里创建一个 MCVE,但我得到了:

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

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

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

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?

推荐答案

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

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

之所以有效,是因为 Iterator 类型的可变指针实现了 Iterator 特征.聪明!

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 { ... }

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

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

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

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.

解决方案,不要使用 Peekable 而是 &mut Peekable.您还需要指定生命周期:

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

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

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.

现在我终于明白了,我认为更改 struct CautiousTakeWhile 的定义以将可窥视位包含到结构本身中可能是一个好主意.如果我是对的,困难在于必须手动指定生命周期.比如:

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的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持!

05-28 10:58
查看更多