如何为盒装值实现迭代器?

How to implement Iterator for boxed values?

我有一个结构,它通过 next 方法从特征 Iterator:

给出数字
struct Numbers{
    number: usize,
    count: usize
}

impl Iterator for Numbers {
    type Item = usize;

    fn next(&mut self) -> Option<Self::Item> {
        if self.count > 0 {
            self.count -= 1;
            return Some(self.number);
        }

        return None;
    }
}

fn main(){
    let numbers = Numbers{
        number: 777,
        count: 10
    };

    for n in numbers {
        println!{"{:?}", n};
    }
}

它与 usize 类型一起正常工作。 但是与 Box 类型相同的代码会出现编译错误:

struct Numbers{
    number: Box<usize>,
    count: usize
}

impl Iterator for Numbers {
    type Item = Box<usize>;

    fn next(&mut self) -> Option<Self::Item> {
        if self.count > 0 {
            self.count -= 1;
            return Some(self.number);
        }

        return None;
    }
}

fn main(){
    let numbers = Numbers{
        number: Box::new(777),
        count: 10
    };

    for n in numbers {
        println!{"{:?}", n};
    }
}

./numbers.rs:12:25: 12:29 error: cannot move out of borrowed content

./numbers.rs:12 return Some(self.number);

如何正确实现盒装值的迭代器?

这归结为 Rust 的所有权模型以及复制和移动语义之间的区别; Box<T> 具有移动语义,未实现 Copy,因此 return Some(self.number); 将移动 self.number,并获得它的所有权;但这是不允许的,因为它需要消耗 self,这仅由可变引用获取。

你有几个选择(我写“具有移动语义的对象”,我的意思是在这种特定情况下self.number):

  1. 不要return具有移动语义的对象,return其他具有复制语义引用的对象,例如引用而不是装箱值(return引用将要求迭代器对象与被迭代的对象不同,以便您可以在 Item 中写入生命周期;因此它不适用于您的特定用例)或未装箱的数字。

  2. 根据具有移动语义的对象构造一个新值到return:

    impl Iterator for Numbers {
        type Item = Box<usize>;
    
        fn next(&mut self) -> Option<Self::Item> {
            if self.count > 0 {
                self.count -= 1;
                Some(Box::new(self.number))
            } else {
                None
            }
        }
    }
    
  3. 使用移动语义克隆对象(这是第二个选项的简化形式,真的):

    impl Iterator for Numbers {
        type Item = Box<usize>;
    
        fn next(&mut self) -> Option<Self::Item> {
            if self.count > 0 {
                self.count -= 1;
                Some(self.number.clone())
            } else {
                None
            }
        }
    }
    
  4. 构造一个新值来替换具有移动语义的对象:

    use std::mem;
    
    impl Iterator for Numbers {
        type Item = Box<usize>;
    
        fn next(&mut self) -> Option<Self::Item> {
            if self.count > 0 {
                self.count -= 1;
                let number = mem::replace(&mut self.number, Box::new(0));
                // self.number now contains 0
                Some(number)
            } else {
                None
            }
        }
    }