微信公众号搜"智元新知"关注
微信扫一扫可直接关注哦!

为什么by_ref不能阻止.all使用迭代器?

如何解决为什么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
}

Playground

以下先打印true,然后再打印0

fn main() {
    let mut a = (1..10);
    println!("{}",a.by_ref().all(|x| x < 10)); // true
    println!("{}",a.count()); // 0
}

Playground

调用.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 举报,一经查实,本站将立刻删除。