使用BigUint实现迭代器遇“cannot move out of borrowed content”错误求助
修复BigUint斐波那契迭代器的“cannot move out of borrowed content”错误
你猜的完全正确!BigUint没有实现Copy trait,这就是那些报错的根源——next方法手里只有&mut self(结构体的可变借用),不允许直接移动借用对象内部的值,而直接操作self.a和self.b会触发Rust的移动语义检查。
下面给你两种可行的修复方案,第二种还能优化性能:
方案一:用克隆快速解决(最直观)
既然BigUint实现了Clone trait,我们可以在需要使用值的地方先克隆一份,这样原有的值不会被移动,只是复制一份出来使用:
extern crate num_bigint; use num_bigint::{BigUint, ToBigUint}; struct FibState { a: BigUint, b: BigUint, } impl Iterator for FibState { type Item = BigUint; fn next(&mut self) -> Option<BigUint> { // 克隆a和b来做加法,避免移动原对象里的值 let next_b = self.a.clone() + self.b.clone(); // 更新状态时也克隆,保证原有的b不会被移走 self.a = self.b.clone(); self.b = next_b; // 返回当前a的克隆,同样不能直接移走self.a Some(self.a.clone()) } } fn fibs_0() -> FibState { FibState { a: 0.to_biguint().unwrap(), b: 1.to_biguint().unwrap(), } } fn fib2(n: usize) -> BigUint { if n < 2 { n.to_biguint().unwrap() } else { fibs_0().skip(n - 1).next().unwrap() } } fn main() { println!("Fib1(300) = {}", fib2(300)); }
方案二:用临时变量优化(减少克隆次数)
上面的方案虽然能跑,但多次克隆BigUint(本身是大整数)会带来不必要的性能开销。我们可以调整逻辑,只在必要的时候克隆一次:
extern crate num_bigint; use num_bigint::{BigUint, ToBigUint}; struct FibState { a: BigUint, b: BigUint, } impl Iterator for FibState { type Item = BigUint; fn next(&mut self) -> Option<BigUint> { // 先把当前的a克隆下来,作为这次要返回的结果 let current_a = self.a.clone(); // 直接拿self.a和self.b的所有权计算下一个b,因为之后不需要原来的a了 let next_b = self.a + self.b; // 把当前的b移给self.a,新的b移给self.b——这里都是移动,不用克隆 self.a = self.b; self.b = next_b; // 返回之前保存的current_a Some(current_a) } } fn fibs_0() -> FibState { FibState { a: 0.to_biguint().unwrap(), b: 1.to_biguint().unwrap(), } } fn fib2(n: usize) -> BigUint { if n < 2 { n.to_biguint().unwrap() } else { fibs_0().skip(n - 1).next().unwrap() } } fn main() { println!("Fib1(300) = {}", fib2(300)); }
为什么这个方案更好?
- 全程只克隆了一次
self.a作为返回值,其余操作都是值的移动,没有额外的内存复制开销 - 逻辑更贴合斐波那契迭代的本质:每次返回当前的a,然后把a更新为之前的b,b更新为a+b
测试运行
修改后的代码可以正常编译,运行后会输出第300个斐波那契数的正确结果。
内容的提问来源于stack exchange,提问作者Gong-Yi Liao
相关产品推荐
相关产品推荐

