如何解决为什么by_ref不能阻止.all使用迭代器?
以下将按预期打印9
,然后打印true
:
fn main() {
let mut a = (1..10);
println!("{}",a.by_ref().count()); // 9
println!("{}",a.all(|x| x < 10)); // true
}
以下先打印true
,然后再打印0
!
fn main() {
let mut a = (1..10);
println!("{}",a.by_ref().all(|x| x < 10)); // true
println!("{}",a.count()); // 0
}
在调用.by_ref()
之前是否不应该在迭代器上调用.all
来防止.all
消耗迭代器?
解决方法
其他答案涵盖了实现方面的情况,但我想讲一下术语,我认为这是造成混乱的根源:
在调用
.by_ref()
之前是否不应该在迭代器上调用.all
来防止.all
消耗迭代器?
在Rust中,消费有一个与所有权有关的狭义定义-一个“消费”值的函数从调用者那里获得了该值的所有权。由于该函数可以随意销毁该值或将其传递,因此该值无法由最初拥有它的调用者进一步使用。
在值实现Iterator
的情况下,使用它们的方法(例如count()
或sum()
)通常也会耗尽它们(用光它们)。其他方法,例如map()
或enumerate()
,将消耗迭代器并返回一个新的迭代器,前提是该原始迭代器自身将被耗尽。但是,还有take()
或scan
之类的方法,它们消耗迭代器而不必耗尽它,即使返回的迭代器被完全耗尽。使用by_ref()
这样的方法可以很方便地使原始迭代器可用于进一步处理:
let mut iter = 1..1000;
let sum_first_50 = iter.by_ref().take(50).sum();
let sum_second_50 = iter.by_ref().take(50).sum();
// ... iter available to produce the remaining 899 numbers ...
第一行中没有by_ref()
,第二行将不会编译,因为第一行take()
将消耗(而不是精疲力竭 )iter
。使用by_ref()
iter
既不会消耗(因为by_ref()
保护它),也不会耗尽(因为我们将它与take()
结合了)。将by_ref()
与同时消耗和耗尽迭代器的方法(例如count()
)结合使用是明确定义的,但却是无用的,因为它只会使您拥有耗尽的迭代器。
如果要防止迭代器用尽(或以其他方式更改),可以克隆它:
fn main() {
let a = 1..10;
println!("{}",a.clone().all(|x| x < 10)); // true
println!("{}",a.count()); // 9
}
,
在迭代器上调用all()
或count()
将多次调用next()
。
即使迭代器不被使用(移出),由于next()
的重复调用,其内部状态也已更改。
当all()
以true
结尾时,已到达序列的末尾,因此count()
仍可调用,但产生0
。
在第一种情况下,count()
到达序列的末尾,但是documentation of all()
说true
返回的是空序列。
每个迭代器适配器(例如.take
,.filter
,当然还有.all
)都只能通过.next
函数访问迭代器的元素。 / p>
.by_ref
唯一要做的是,它允许您在使用迭代器适配器之后继续使用迭代器。任何消耗的元素仍将被消耗。如果您不希望这样做,则应该克隆迭代器。
在Iterator :: by_ref:
的文档中对此进行了解释let a = [1,2,3];
let iter = a.iter();
let sum: i32 = iter.take(5).fold(0,|acc,i| acc + i);
assert_eq!(sum,6);
// if we try to use iter again,it won't work. The following line
// gives "error: use of moved value: `iter`
// assert_eq!(iter.next(),None);
// let's try that again
let a = [1,3];
let mut iter = a.iter();
// instead,we add in a .by_ref()
let sum: i32 = iter.by_ref().take(2).fold(0,3);
// now this is just fine:
assert_eq!(iter.next(),Some(&3));
assert_eq!(iter.next(),None);
版权声明:本文内容由互联网用户自发贡献,该文观点与技术仅代表作者本人。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如发现本站有涉嫌侵权/违法违规的内容, 请发送邮件至 dio@foxmail.com 举报,一经查实,本站将立刻删除。