代码之家  ›  专栏  ›  技术社区  ›  Amandasaurus

我如何在一个trait上实现迭代器,它返回一个具有生存期引用的结构?[复制]

  •  0
  • Amandasaurus  · 技术社区  · 7 年前

    我无法表示 Iterator 实施。如何在不更改迭代器返回值的情况下编译此代码?我希望它返回一个引用向量。

    很明显,我没有正确使用lifetime参数,但是在尝试了各种方法之后,我放弃了,我不知道该如何处理它。

    use std::iter::Iterator;
    
    struct PermutationIterator<T> {
        vs: Vec<Vec<T>>,
        is: Vec<usize>,
    }
    
    impl<T> PermutationIterator<T> {
        fn new() -> PermutationIterator<T> {
            PermutationIterator {
                vs: vec![],
                is: vec![],
            }
        }
    
        fn add(&mut self, v: Vec<T>) {
            self.vs.push(v);
            self.is.push(0);
        }
    }
    
    impl<T> Iterator for PermutationIterator<T> {
        type Item = Vec<&'a T>;
        fn next(&mut self) -> Option<Vec<&T>> {
            'outer: loop {
                for i in 0..self.vs.len() {
                    if self.is[i] >= self.vs[i].len() {
                        if i == 0 {
                            return None; // we are done
                        }
                        self.is[i] = 0;
                        self.is[i - 1] += 1;
                        continue 'outer;
                    }
                }
    
                let mut result = vec![];
    
                for i in 0..self.vs.len() {
                    let index = self.is[i];
                    result.push(self.vs[i].get(index).unwrap());
                }
    
                *self.is.last_mut().unwrap() += 1;
    
                return Some(result);
            }
        }
    }
    
    fn main() {
        let v1: Vec<_> = (1..3).collect();
        let v2: Vec<_> = (3..5).collect();
        let v3: Vec<_> = (1..6).collect();
    
        let mut i = PermutationIterator::new();
        i.add(v1);
        i.add(v2);
        i.add(v3);
    
        loop {
            match i.next() {
                Some(v) => {
                    println!("{:?}", v);
                }
                None => {
                    break;
                }
            }
        }
    }
    

    ( Playground link )

    error[E0261]: use of undeclared lifetime name `'a`
      --> src/main.rs:23:22
       |
    23 |     type Item = Vec<&'a T>;
       |                      ^^ undeclared lifetime
    
    0 回复  |  直到 8 年前
        1
  •  29
  •   Vladimir Matveev    10 年前

    据我所知,你希望迭代器返回一个引用向量到它自身,对吗?不幸的是,在铁锈中是不可能的。

    这是修剪过的 Iterator 特质:

    trait Iterator {
        type Item;
        fn next(&mut self) -> Option<Item>;
    }
    

    请注意 之间 &mut self Option<Item> . 这意味着 next() 方法无法将引用返回到迭代器本身。你不能表达一辈子的返回引用。这基本上就是你找不到一种方法来指定正确的生存期的原因-它应该是这样的:

    fn next<'a>(&'a mut self) -> Option<Vec<&'a T>>
    

    但这不是一个有效的 方法 迭代器 特质。

    这样的迭代器(可以将引用返回自身的迭代器)称为 流迭代器 . 你可以找到更多 here , here here ,如果你愿意的话。

    但是,您可以从迭代器返回对其他结构的引用—这就是大多数集合迭代器的工作方式。可能是这样的:

    pub struct PermutationIterator<'a, T> {
        vs: &'a [Vec<T>],
        is: Vec<usize>
    }
    
    impl<'a, T> Iterator for PermutationIterator<'a, T> {
        type Item = Vec<&'a T>;
    
        fn next(&mut self) -> Option<Vec<&'a T>> {
            ...
        }
    }
    

    'a 现在宣布 impl 阻止。这样做是可以的(事实上是必需的),因为您需要在结构上指定lifetime参数。你可以用同样的方法 “a” Item 下一步()

        2
  •  7
  •   Community Mohan Dere    8 年前

    @VladimirMatveev's answer 它的解释是正确的 您的代码无法编译。简而言之,它说明迭代器不能从自身产生借用的值。

    然而,它可以从其他东西那里获得借来的价值。这就是我们所要达到的目的 Vec Iter Vec公司 拥有价值观 只是一个包装器能够在 Vec公司

    这是一个能达到你想要的设计。迭代器就像 Iter公司 ,只是对实际拥有值的其他容器的包装。

    use std::iter::Iterator;
    
    struct PermutationIterator<'a, T: 'a> {
        vs : Vec<&'a [T]>,
        is : Vec<usize>
    }
    
    impl<'a, T> PermutationIterator<'a, T> {
        fn new() -> PermutationIterator<'a, T> { ... }
    
        fn add(&mut self, v : &'a [T]) { ... }
    }
    
    impl<'a, T> Iterator for PermutationIterator<'a, T> {
        type Item = Vec<&'a T>;
        fn next(&mut self) -> Option<Vec<&'a T>> { ... }
    }
    
    fn main() {
        let v1 : Vec<i32> = (1..3).collect();
        let v2 : Vec<i32> = (3..5).collect();
        let v3 : Vec<i32> = (1..6).collect();
    
        let mut i = PermutationIterator::new();
        i.add(&v1);
        i.add(&v2);
        i.add(&v3);
    
        loop {
            match i.next() {
                Some(v) => { println!("{:?}", v); }
                None => {break;}
            }
        }
    }
    

    (Playground)


    与你最初的问题无关。如果这只是我,我会确保所有借来的向量都能一次得到。这样做的目的是消除 add 在施工时直接传递所有借用向量:

    use std::iter::{Iterator, repeat};
    
    struct PermutationIterator<'a, T: 'a> {
        ...
    }
    
    impl<'a, T> PermutationIterator<'a, T> {
        fn new(vs: Vec<&'a [T]>) -> PermutationIterator<'a, T> {
            let n = vs.len();
            PermutationIterator {
                vs: vs,
                is: repeat(0).take(n).collect(),
            }
        }
    }
    
    impl<'a, T> Iterator for PermutationIterator<'a, T> {
        ...
    }
    
    fn main() {
        let v1 : Vec<i32> = (1..3).collect();
        let v2 : Vec<i32> = (3..5).collect();
        let v3 : Vec<i32> = (1..6).collect();
        let vall: Vec<&[i32]> = vec![&v1, &v2, &v3];
    
        let mut i = PermutationIterator::new(vall);
    }
    

    (Playground)

    ( 编辑 Vec<&'a [T]> 而不是 Vec<Vec<&'a T>> . 将ref带到容器比构建ref容器更容易。)

        3
  •  3
  •   Shepmaster Tim Diekmann    7 年前

    如其他答案所述,这被称为 流迭代器 它需要不同于Rust的保证 Iterator streaming-iterator 它提供了 StreamingIterator 特质。

    以下是实现特征的一个示例:

    extern crate streaming_iterator;
    
    use streaming_iterator::StreamingIterator;
    
    struct Demonstration {
        scores: Vec<i32>,
        position: usize,
    }
    
    // Since `StreamingIterator` requires that we be able to call
    // `advance` before `get`, we have to start "before" the first
    // element. We assume that there will never be the maximum number of
    // entries in the `Vec`, so we use `usize::MAX` as our sentinel value.
    impl Demonstration {
        fn new() -> Self {
            Demonstration {
                scores: vec![1, 2, 3],
                position: std::usize::MAX,
            }
        }
    
        fn reset(&mut self) {
            self.position = std::usize::MAX;
        }
    }
    
    impl StreamingIterator for Demonstration {
        type Item = i32;
    
        fn advance(&mut self) {
            self.position = self.position.wrapping_add(1);
        }
    
        fn get(&self) -> Option<&Self::Item> {
            self.scores.get(self.position)
        }
    }
    
    fn main() {
        let mut example = Demonstration::new();
    
        loop {
            example.advance();
            match example.get() {
                Some(v) => {
                    println!("v: {}", v);
                }
                None => break,
            }
        }
    
        example.reset();
    
        loop {
            example.advance();
            match example.get() {
                Some(v) => {
                    println!("v: {}", v);
                }
                None => break,
            }
        }
    }
    

    generic associated types (GATs) 从RFC 1598开始执行。