如何复用range获取数组切片?避免频繁调用range.clone()的方法
解决Range的Moved Value错误,避免频繁clone()
嘿,这个问题我之前在写数组分块逻辑的时候也踩过坑!其实核心是Rust的所有权机制在搞事情,咱们一步步来拆解解决办法~
首先得搞清楚为什么会触发moved value错误:当你直接使用range而不是&range时,Rust默认会转移这个range的所有权——如果之后你还要再用到这个range变量,自然就会报错说它已经被move走了。而clone()是强行复制一份新的range,但频繁调用确实没必要,咱们有更优的方案:
情况1:你的Range元素是Copy类型(比如usize、i32)
如果你的range是0..10这种基于基本数值类型的,那其实根本不需要clone!因为Range<T>在T是Copy类型时,它本身也是Copy的——也就是说,每次使用它都会自动复制一份,不会转移原变量的所有权。比如:
let arr = [1,2,3,4,5,6]; let r = 0..3; // 直接用r,不会触发move let chunk1 = &arr[r]; // 再次用r完全没问题,因为Copy了一份新的Range let chunk2 = &arr[r];
如果这时候你还是遇到了move错误,大概率是你把range传递给了一个接收所有权的函数。这时候改成传递引用就行——把函数参数改成&Range<T>,调用时传&r,这样就不会转移所有权,自然不用clone。
情况2:你的Range类型不是Copy(比如RangeInclusive、自定义非Copy元素)
如果是这种场景,咱们有两个更高效的替代方案,比clone香多了:
- 传递引用而非所有权:让需要range的函数/逻辑接受
&Range<T>或者&mut Range<T>(如果需要修改range的话),这样原range的所有权始终在你手里,不用复制。 - 重新生成range:如果你的range是可以通过已知的start和end值重新创建的,那每次需要的时候直接写
start..end就行——比如分块时,每次计算好新的起始和结束索引,直接生成新的range,完全不用复用旧的,也就没了clone的开销。 - 用by_ref()保留所有权:如果是在迭代range的元素,那可以用
range.by_ref()获取一个引用迭代器,迭代过程中不会拿走原range的所有权,迭代结束后还能继续使用原range:
let mut r = 0..10; // 用by_ref()迭代前3个元素,不转移所有权 for num in r.by_ref().take(3) { println!("分块元素:{}", num); } // 之后还能继续使用原range for num in r { println!("剩余元素:{}", num); }
总结一下:先检查你的Range是不是Copy类型,是就直接用;不是的话优先用引用或者重新生成range,这俩方法都能彻底避免频繁clone()的麻烦~
内容的提问来源于stack exchange,提问作者Ernest
相关产品推荐
相关产品推荐

