通过借用一个大小的 Range<T> 来迭代它
Iterate through a sized Range<T> by borrowing it
遍历 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
loops desugar to a call to std::iter::IntoIterator::into_iter
, which is implemented for everything which is already an iterator (since you can obviously create an iterator from an iterator -- just return the iterator). Additionally, Iterator
is implemented for (and only for) &mut
references to existing iterators。
由此我们可以推断出错误:
- 您可以迭代任何实现了
IntoIterator
. 的东西
- 您可以将任何
Iterator
变成 Iterator
到 IntoIterator
。什么都不做。
Iterator
仅针对对其他 Iterator
的唯一 (&mut
) 引用实施。
因此,您不能迭代 &Range
s,而只能迭代 &mut Range
s 或 Range
s。
应该做的是 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);
}
这是非常便宜的。
此外,这些关于 &mut
而不是 &
引用的 Iterator
特征实现的规则适用于所有迭代器。这允许我们做这样的事情:
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
。
遍历 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
loops desugar to a call to std::iter::IntoIterator::into_iter
, which is implemented for everything which is already an iterator (since you can obviously create an iterator from an iterator -- just return the iterator). Additionally, Iterator
is implemented for (and only for) &mut
references to existing iterators。
由此我们可以推断出错误:
- 您可以迭代任何实现了
IntoIterator
. 的东西
- 您可以将任何
Iterator
变成Iterator
到IntoIterator
。什么都不做。 Iterator
仅针对对其他Iterator
的唯一 (&mut
) 引用实施。
因此,您不能迭代 &Range
s,而只能迭代 &mut Range
s 或 Range
s。
应该做的是 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);
}
这是非常便宜的。
此外,这些关于 &mut
而不是 &
引用的 Iterator
特征实现的规则适用于所有迭代器。这允许我们做这样的事情:
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
。