输入一个闭包,该闭包返回从其输入之一借用的匿名类型,而无需堆分配或特征对象

gvl*_*gvl 6 lifetime rust

假设我有以下工作代码:

use std::collections::VecDeque;

fn modify<S, F>(state: &mut S, func: F)
where
    F: for<'a> Fn(&'a mut S) -> Box<dyn Iterator<Item = &mut u64> + 'a>
{
    let mut prev = 1;
    for _ in 0..3 {
        for item in func(state) {
            let val = *item;
            *item = val * prev;
            prev = val;
        }
    }
}

fn main() {
    let mut state: VecDeque<u64> = vec![1,2,3,4].into();

    modify(&mut state, |s| Box::new(s.iter_mut()));
    assert_eq!(state, [48, 8, 24, 864]);

    modify(&mut state, |s| Box::new(s.iter_mut().take(2)));
    assert_eq!(state, [147456, 7077888, 24, 864]);

    modify(&mut state, |s| Box::new(s.iter_mut().skip(2)));
    assert_eq!(state, [147456, 7077888, 429981696, 10319560704]);
}
Run Code Online (Sandbox Code Playgroud)

modifystate接受一个函数,该函数根据给定变量(在本例中为 a )多次生成迭代器VecDeque。该函数可以工作,但包含不必要的堆分配以及特征对象形式的不必要的多态性。我非常想做这样的事情:

use std::collections::VecDeque;

fn modify<'a, S, F, I>(state: &'a mut S, func: F)
where
    F: Fn(&'a mut S) -> I,
    I: Iterator<Item = &'a mut u64>
{
    let mut prev = 1;
    for _ in 0..3 {
        for item in func(state) {
            let val = *item;
            *item = val * prev;
            prev = val;
        }
    }
}

fn main() {
    let mut state: VecDeque<u64> = vec![1,2,3,4].into();

    modify(&mut state, |s| s.iter_mut());
    assert_eq!(state, [48, 8, 24, 864]);

    modify(&mut state, |s| s.iter_mut().take(2));
    assert_eq!(state, [147456, 7077888, 24, 864]);

    modify(&mut state, |s| s.iter_mut().skip(2));
    assert_eq!(state, [147456, 7077888, 429981696, 10319560704]);
}
Run Code Online (Sandbox Code Playgroud)

但我现在得到这个错误:

error[E0499]: cannot borrow `*state` as mutable more than once at a time
  --> src/main.rs:10:26
   |
3  | fn modify<'a, S, F, I>(state: &'a mut S, func: F)
   |           -- lifetime `'a` defined here
...
10 |         for item in func(state) {
   |                     -----^^^^^-
   |                     |    |
   |                     |    `*state` was mutably borrowed here in the previous iteration of the loop
   |                     argument requires that `*state` is borrowed for `'a`

For more information about this error, try `rustc --explain E0499`.
Run Code Online (Sandbox Code Playgroud)

我不知道如何说服借用检查员做我想做的事。任何线索将不胜感激。谢谢!

Evi*_*Tak 2

长话短说

不,直到关闭 HRTB 推断得到修复。当前的解决方法包括使用函数指针,或者在自定义结构上实现辅助特征——无论采用哪种方法,在 Rust 中引入更高种类的类型之前,都需要辅助特征。

操场

细节

为了避免返回 a Box,您需要类型参数在生命周期内I通用的'a,以便您可以在任何生命周期中使用它(for<'a>例如,在界限内)。不幸的是,正如在类似问题中所讨论的,Rust 尚不支持更高种类的类型(类型参数本身比其他类型参数更通用),因此我们必须使用辅助特征:

trait GenerateIterator<'a, S: 'a> {
    type Output: Iterator<Item = &'a mut u64>;
    fn generate(self, s: &'a mut S) -> Self::Output;
}

impl<'a, S: 'a, I, F> GenerateIterator<'a, S> for F
where
    F: Fn(&'a mut S) -> I,
    I: Iterator<Item = &'a mut u64>,
{
    type Output = I;
    fn generate(self, s: &'a mut S) -> Self::Output {
        self(s)
    }
}

fn modify<S>(state: &mut S, func: impl for<'a> GenerateIterator<'a, S>) {
    let mut prev = 1;
    for _ in 0..3 {
        for item in func.generate(state) {
            let val = *item;
            *item = val * prev;
            prev = val;
        }
    }
}
Run Code Online (Sandbox Code Playgroud)

这对于帮助我们解决在这种情况下使用更高种类类型的问题很有帮助,但是由于闭包 HRTB(更高等级特征界限)推理中的另一个编译器限制,编译器无法推断我们传递给的闭包modify是在任何一生中都是通用的。另一种方法是使用函数指针,如VecDeque::iter_mut,或创建您自己的structs 来实现GenerateIterator生成Iterator您想要的 :

fn main() {
    fn take2(s: &mut VecDeque<u64>) -> impl Iterator<Item = &mut u64> {
        s.iter_mut().take(2)
    }

    fn skip2(s: &mut VecDeque<u64>) -> impl Iterator<Item = &mut u64> {
        s.iter_mut().skip(2)
    }

    let mut state: VecDeque<u64> = vec![1, 2, 3, 4].into();

    modify(&mut state, VecDeque::iter_mut);
    assert_eq!(state, [48, 8, 24, 864]);

    modify(&mut state, take2);
    assert_eq!(state, [147456, 7077888, 24, 864]);

    modify(&mut state, skip2);
    assert_eq!(state, [147456, 7077888, 429981696, 10319560704]);
}
Run Code Online (Sandbox Code Playgroud)