【问题标题】:Writing an iterator [duplicate]编写迭代器[重复]
【发布时间】:2015-02-20 11:01:34
【问题描述】:

编者注:此代码示例来自 Rust 1.0 之前的版本,不是有效的 Rust 1.0 代码。由于更改了 for 循环的实现方式,此代码的更新版本不再产生错误。

我正在用 Rust 编写一个 Vector 结构。

pub struct Vector {
    pub x: f32,
    pub y: f32,
    pub z: f32,

    curr: uint
}

我想为它写一个简单的迭代器,这样我就可以迭代向量的元素。它有时很有用,而且我对 Rust 中的迭代器几乎一无所知。

这是我目前所拥有的。

impl Iterator<f32> for Vector {
    fn next(&mut self) -> Option<f32> {
        let new_next : Option<f32> = match self.curr {
            0 => Some(self.x),
            1 => Some(self.y),
            2 => Some(self.z), 
            _ => None
        };
        let new_curr = (self.curr + 1) % 4;
        mem::replace(&mut self.curr, new_curr);
        new_next
    }
}

现在理想情况下,我希望能够像这样使用它:

let u = Vector::new(0.0f32, 0.0f32, 0.0f32);
for element in u {
    ///
}

但是,我收到以下编译器错误:

 error: cannot borrow immutable local variable `u` as mutable

所以我很难过。经过几个小时的谷歌搜索,我想不出任何东西。我觉得我错过了一些巨大的东西。

【问题讨论】:

  • 请更新此问题或在标题中将其标记为已过时;迭代器现在使用关联类型,这个问题不再反映在问题或答案中实现它们的正确方法。

标签: iterator rust


【解决方案1】:

编者注:由于 for 循环的工作方式发生了变化,从 Rust 1.0 开始,此答案不再有用。

Vladimir Matveev 的回答是正确的,并解释了您应该做什么。我想进一步解释你的错误。

错误:不能将不可变的局部变量 u 借用为可变的

当您迭代某些东西时,您需要改变跟踪您所在位置的 something。在您的代码中,这是由以下人员完成的:

mem::replace(&mut self.curr, new_curr);

Rust 知道你想要改变哪个东西,因为 next 的方法签名表明了这一点:

fn next(&mut self) -> Option<f32>

问题是你的对象不是可变的

let u = Vector::new(0.0f32, 0.0f32, 0.0f32);

如果您将代码更改为

let mut u = Vector::new(0.0f32, 0.0f32, 0.0f32);

我希望您的代码能够按原样工作。话虽如此,单独的迭代器可能是正确的方法。但是,您会比我们更了解您的代码!

【讨论】:

    【解决方案2】:

    你确定你真的想让Vector 它自己 成为一个迭代器吗?通常结构和迭代器是分开的。考虑这样的事情:

    pub struct Vector {
        pub x: f32,
        pub y: f32,
        pub z: f32,
    }
    
    pub struct VectorIter<'a> {
        vector: &'a Vector,
        cur: usize,
    }
    
    impl<'a> Iterator for VectorIter<'a> {
        type Item = f32;
    
        fn next(&mut self) -> Option<f32> {
            let r = match self.cur {
                0 => self.vector.x,
                1 => self.vector.y,
                2 => self.vector.z,
                _ => return None,
            };
            self.cur += 1;
            Some(r)
        }
    }
    
    impl Vector {
        fn iter(&self) -> VectorIter {
            VectorIter {
                vector: self,
                cur: 0,
            }
        }
    }
    
    fn main() {
        let v = Vector { x: 1.0, y: 2.0, z: 3.0 };
        for c in v.iter() {
            println!("{}", c);
        }
    }
    

    因为Vector很简单,所以可以推导出Copy,它的迭代器可以取值:

    #[derive(Copy, Clone)]
    pub struct Vector {
        pub x: f32,
        pub y: f32,
        pub z: f32,
    }
    
    pub struct VectorIter {
        vector: Vector,
        cur: usize,
    }
    
    impl Iterator for VectorIter {
        type Item = f32;
        fn next(&mut self) -> Option<f32> {
            let r = match self.cur {
                0 => self.vector.x,
                1 => self.vector.y,
                2 => self.vector.z,
                _ => return None,
            };
            self.cur += 1;
            Some(r)
        }
    }
    
    impl Vector {
        fn iter(&self) -> VectorIter {
            VectorIter {
                vector: *self,
                cur: 0,
            }
        }
    }
    
    fn main() {
        let v = Vector { x: 1.0, y: 2.0, z: 3.0 };
        for c in v.iter() {
            println!("{}", c);
        }
    }
    

    除非您的Vector 包含坐标以外的其他内容,否则此变体可能会更好。这个变体更灵活,因为它不会将迭代器与可迭代绑定,但另一方面,正是由于同样的原因,它可能是不可取的(使用Copy,您可以更改原始值,而迭代器不会反映它;没有Copy 和引用,您将根本无法更改原始值)。您想要使用的语义很大程度上取决于您的用例。

    【讨论】:

    • 这更有意义。非常感谢!
    • 我认为当你实现迭代器时,你必须指定类型别名type Item = f32;。我无法在 1.7.0 上编译此代码。
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 2013-05-01
    • 1970-01-01
    • 1970-01-01
    • 2015-01-01
    • 2012-03-23
    • 2018-05-24
    • 2018-09-17
    相关资源
    最近更新 更多