【问题标题】:How to implement Iterator for boxed values?如何为装箱值实现迭代器?
【发布时间】:2015-05-17 21:38:14
【问题描述】:

我有一个结构,它通过方法 next 来自 trait 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);

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

【问题讨论】:

    标签: rust


    【解决方案1】:

    这归结为 Rust 的所有权模型以及复制和移动语义之间的区别; Box&lt;T&gt; 有移动语义,没有实现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
              }
          }
      }
      

    【讨论】:

      猜你喜欢
      • 2018-06-19
      • 2016-01-23
      • 1970-01-01
      • 2020-10-02
      • 2012-02-18
      • 2013-12-10
      • 2015-02-19
      • 2021-05-22
      相关资源
      最近更新 更多