如何表示返回泛型借用迭代器的函数的Rust生存期

zc0qhyus  于 2023-04-12  发布在  其他
关注(0)|答案(2)|浏览(149)

我想在一个结构体中有一个函数,它接受一个状态并返回一个迭代器。到目前为止,这是可行的,除非我想让迭代器从状态中借用,这应该是可以的,但我不知道如何表达生存期。
第一个例子运行得很好,因为Vec被克隆了,但是出于性能考虑,我不想克隆。

use std::fmt::Display;

struct State {
    items: Vec<i32>,
}

struct HasIteratorFunction<T: Display, I: Iterator<Item = T>> {
    iterator: Box<dyn Fn(&State) -> I>,
}
impl<T: Display, I: Iterator<Item = T>> HasIteratorFunction<T, I> {
    fn print_items(&self, state: &State) {
        for item in (self.iterator)(state) {
            println!("{}", item);
        }
    }
}

fn main() {
    // this works
    let it = HasIteratorFunction {
        iterator: Box::new(|state| state.items.clone().into_iter())
    };
    it.print_items(&State { items: vec![1, 2, 3] });
    
    // this doesn't
    let it_without_cloning = HasIteratorFunction {
        iterator: Box::new(|state| state.items.iter())
    };
    it_without_cloning.print_items(&State { items: vec![4, 5, 6] });
}

真实的的代码将更加通用,因此返回切片而不是通用迭代器将不起作用。

bprjcwpo

bprjcwpo1#

HasIteratorFunction结构体中存储的回调函数中为State添加一个显式的生存期,并为相同的生存期添加一个绑定到I的生存期。

use std::fmt::Display;

struct State {
    items: Vec<i32>,
}

struct HasIteratorFunction<'a, T: Display, I: Iterator<Item = T> + 'a> {
    iterator: Box<dyn Fn(&'a State) -> I>,
}
impl<'a, T: Display, I: Iterator<Item = T> + 'a> HasIteratorFunction<'a, T, I> {
    fn print_items(&self, state: &'a State) {
        for item in (self.iterator)(state) {
            println!("{}", item);
        }
    }
}

fn main() {
    let state = State { items: vec![1, 2, 3] };
    
    // this works
    let it = HasIteratorFunction {
        iterator: Box::new(|state| state.items.clone().into_iter())
    };
    it.print_items(&state);
    
    let state = State { items: vec![4, 5, 6] };
    
    let it_without_cloning = HasIteratorFunction {
        iterator: Box::new(|state| state.items.iter())
    };
    
    it_without_cloning.print_items(&state);
}

Playground.

44u64gxh

44u64gxh2#

你可以实现类似的东西,但不能用闭包,也不能完全按照要求(注意我添加了copied()):

trait HasIterFn {
    type Item;
    type Iter<'a>: Iterator<Item = Self::Item>;
    fn get_iter<'state>(&self, state: &'state State) -> Self::Iter<'state>;
}

// A shortcut for where the iterator is not borrowing.
impl<F: Fn(&State) -> I, I: Iterator> HasIterFn for F {
    type Item = I::Item;
    type Iter<'a> = I;
    fn get_iter(&self, state: &State) -> I {
        self(state)
    }
}

struct HasIteratorFunction<T: Display, I: HasIterFn<Item = T>> {
    iterator: I,
}
impl<T: Display, I: HasIterFn<Item = T>> HasIteratorFunction<T, I> {
    fn print_items(&self, state: &State) {
        for item in self.iterator.get_iter(state) {
            println!("{}", item);
        }
    }
}

fn main() {
    // this works
    let it = HasIteratorFunction {
        iterator: |state: &State| state.items.clone().into_iter(),
    };
    it.print_items(&State { items: vec![1, 2, 3] });
    
    // this doesn't
    let it_without_cloning = HasIteratorFunction {
        iterator: {
            struct Func;
            impl HasIterFn for Func {
                type Item = i32;
                type Iter<'a> = std::iter::Copied<std::slice::Iter<'a, i32>>;
                fn get_iter<'state>(&self, state: &'state State) -> Self::Iter<'state> {
                    state.items.iter().copied()
                }
            }
            Func
        }
    };
    it_without_cloning.print_items(&State { items: vec![4, 5, 6] });
}

在未来,你可能能够更好地实现这一点,也许没有copied(),但目前,由于Fn特征的设计方式和类型系统的限制,恕我直言,这是你能得到的最好的。

相关问题