1

迭代 aRange<T>似乎消耗了范围实例,因为into_iter函数获取了范围的所有权。通过查看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()是可用的,但这也会限制我们作为不可变借用,因为我们已经有了对同一个对象的可变借用。

4

1 回答 1

4

首先,让我们看一下实现:

Range实现Iteratorfor将 desugar 循环到对 的调用std::iter::IntoIterator::into_iter,该调用针对已经是迭代器的所有内容实现(因为您显然可以从迭代器创建迭代器——只需返回迭代器)。此外,Iterator实现(并且仅用于)&mut对现有迭代器的引用

由此我们可以推断出错误:

  • 您可以迭代任何实现IntoIterator.
  • 您可以将 anyIterator变成Iteratorthrough IntoIterator。什么都不做。
  • Iterator仅针对对其他s的唯一 ( &mut) 引用实现。Iterator

因此,您不能对&Ranges 进行迭代,而只能对&mut Ranges 或Ranges 进行迭代。

相反,应该做的CloneRange

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);
}

这是非常便宜的。


此外,这些关于Iteratortrait for&mut和 not &references 实现的规则适用于所有迭代器。这允许我们做这样的事情:

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需要selfself,所以&mut Range我们不会用完原来的Range.

于 2020-06-20T01:35:28.943 回答