如何实现不消耗自身的迭代器,使Fibonacci实例在循环后仍可复用?
问题:如何让斐波那契迭代器不消耗自身实例?
我编写了一段用于学习的Rust代码,实现了生成斐波那契数列的Fibonacci结构体并为其实现Iterator trait:
struct Fibonacci { curr: u32, next: u32, } impl Iterator for Fibonacci { type Item = u32; fn next(&mut self) -> Option<Self::Item> { let current = self.curr; self.curr = self.next; self.next = current + self.next; Some(current) } } impl Fibonacci { fn new() -> Self { Fibonacci { curr: 0, next: 1 } } fn current(&self) -> u32 { self.curr } } fn main() { println!("The first four terms of the Fibonacci sequence are: "); let fib = Fibonacci::new(); for i in fib.take(4) { println!("> {}", i); } // println!("cur {}", fib.current()); // *fails* }
调用fib.take(4)会转移fib的所有权,导致后续调用fib.current()时出现如下错误:
let fib = Fibonacci::new(); --- move occurs because `fib` has type `Fibonacci`, which does not implement the `Copy` trait for i in fib.take(4) { ------- `fib` moved due to this method call ... println!("cur {}", fib.current()); ^^^^^^^^^^^^^ value borrowed here after move note: this function takes ownership of the receiver `self`, which moves `fib`
请问如何修改实现,让迭代器不消耗自身实例,使循环后的fib变量仍可正常使用?
解决方案
以下几种方式可以实现需求:
方法一:为Fibonacci实现Clone trait
Fibonacci的字段都是实现了Copy的u32类型,直接派生Clone trait,迭代时克隆原实例,这样原实例的所有权不会被转移:
修改结构体定义:
#[derive(Clone)] struct Fibonacci { curr: u32, next: u32, }
调整main函数,克隆实例进行迭代:
fn main() { println!("The first four terms of the Fibonacci sequence are: "); let fib = Fibonacci::new(); for i in fib.clone().take(4) { println!("> {}", i); } println!("cur {}", fib.current()); // 原实例状态保持初始值0,可正常调用 }
如果希望原实例同步迭代进度,只需将fib声明为可变,迭代克隆后的可变实例即可:
fn main() { println!("The first four terms of the Fibonacci sequence are: "); let mut fib = Fibonacci::new(); let mut fib_iter = fib.clone(); for i in fib_iter.take(4) { println!("> {}", i); } fib = fib_iter; // 将迭代后的状态同步回原实例 println!("cur {}", fib.current()); // 此时curr为3 }
方法二:迭代可变引用而非所有权
利用std::iter::from_mut将可变引用转换为迭代器,take操作针对的是引用而非原实例,既不会转移所有权,还能同步更新原实例的状态:
use std::iter::from_mut; fn main() { println!("The first four terms of the Fibonacci sequence are: "); let mut fib = Fibonacci::new(); for i in from_mut(&mut fib).take(4) { println!("> {}", i); } println!("cur {}", fib.current()); // 原实例状态已更新,curr为3 }
方法三:封装自定义迭代器方法(可选)
为Fibonacci添加一个方法,直接返回自身的可变引用迭代器,让代码更直观:
use std::iter::from_mut; impl Fibonacci { // ... 现有方法 ... fn iter(&mut self) -> impl Iterator<Item = u32> + '_ { from_mut(self) } }
在main中使用:
fn main() { println!("The first four terms of the Fibonacci sequence are: "); let mut fib = Fibonacci::new(); for i in fib.iter().take(4) { println!("> {}", i); } println!("cur {}", fib.current()); // 状态同步更新,curr为3 }
内容的提问来源于stack exchange,提问作者binary01
相关产品推荐
相关产品推荐

