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

时间:2015-05-17 21:38:14

标签: rust

我有一个结构,通过方法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错误:无法摆脱借来的内容

     

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

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

1 个答案:

答案 0 :(得分:6)

这归结为Rust的所有权模型以及复制和移动语义之间的区别; Box<T>已移动语义,未实施Copy,因此return Some(self.number);会移动self.number,取得其所有权;但这是不允许的,因为它需要消耗self,这只能通过可变参考来实现。

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

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

  2. 构造一个基于具有移动语义的对象返回的新值:

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