遍历Range<T>
似乎会消耗范围实例,因为into_iter
函数获取范围的所有权。通过查看documentation of range,很明显Borrow
特性仅适用于动态范围对象。如果不进行克隆,是否有可能在范围内进行迭代,同时又将范围的不可变引用传递给其他函数?
let numbers = 500..4000;
// ERROR [(E0277)]: the trait `std::iter::Iterator` is not implemented for `&std::ops::Range<i32>`
for n in &numbers {
println!("{}", n);
do_something_else(&numbers);
reuse_range(&numbers);
}
// Surprisingly, there are no errors when it comes to argument type of functions.
fn do_something_else(range: &Range<i32>) { }
fn reuse_range(range: &Range<i32>) { }
如上所示,函数可以借用
Range<T: Sized>
,但编译器本身不允许借用范围。到目前为止,我已经尝试使用
Box
智能指针,但是行为是相同的。简单来说,就可以使用
by_ref()
,但是由于我们已经可以对同一个对象进行可变的借用,因此这也限制了我们借用不可变的借用。
最佳答案
首先,让我们看一下实现:
Range
implements Iterator
。 for
将desugar循环到对 std::iter::IntoIterator::into_iter
的调用implemented for everything which is already an iterator(因为显然可以从迭代器创建迭代器-只需返回迭代器即可)。另外, Iterator
is implemented for (and only for) &mut
references to existing iterators。
由此我们可以推断出错误:
IntoIterator
的任何对象。 Iterator
将任何Iterator
转换为IntoIterator
。什么都不做。 Iterator
仅对其他&mut
的唯一(Iterator
)引用实现。 因此,您不能在
&Range
上进行迭代,而只能在&mut Range
或Range
上进行迭代。相反,应该对
Clone
the Range
进行操作:let my_range = 10..40;
for i in my_range.clone() {
println!("{:?}", i);
}
对该范围进行可变引用(从而也将其清空):
let mut my_range = 10..40;
for i in &mut my_range {
println!("{:?}", i);
}
assert_eq!(my_range.next(), None);
或者执行每次仅构建范围的更惯用的操作:
for i in 10..40 {
println!("{:?}", i);
}
这样做非常便宜。
此外,这些有关
Iterator
的&mut
特性的实现的规则(而非&
引用)适用于所有迭代器。这使我们可以执行以下操作:let mut my_iter = 0..100;
// Only take first 50 elements.
for x in (&mut my_iter).take(50) {
println!("{:?} < 50", x);
}
for x in my_iter {
println!("{:?} >= 50", x);
}
注意
take
takes self
,但是self
是&mut Range
,因此我们不会用尽原始的Range
。
关于rust - 通过借用它遍历大小合适的Range <T>,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/62480347/