Почему я получаю разные типы аргументов при использовании filter в итераторе?

#filter #rust #reference #iterator #closures

#Фильтр #Ржавчина #ссылка #итератор #замыкания

Вопрос:

Я использую filter , но я не понимаю, почему я должен использовать **x > 1 для среза, но использовать *x > 1 для диапазона.

 fn main() {
    let a = [0, 1, 2, 3];
    let a_iter = a.iter().filter(|x: amp;amp;i32| **x > 1);  // x: amp;amp;i32
    let x: Vec<amp;i32> = a_iter.collect();
    println!("{:?}", x);

    let b = 0..4;
    let b_iter = b.filter(|x: amp;i32| *x > 1);           // x: amp;i32
    let y: Vec<i32> = b_iter.collect();
    println!("{:?}", y);
}
 

В документах говорится, что так и должно быть **x > 1 .

Ответ №1:

slice::iter , например, a.iter() в вашем примере, создает итератор по ссылкам на значения. Range s — это итераторы, которые выдают не ссылочные значения.

filter(<closure>) Метод принимает a <closure> , который принимает значения итератора по ссылке, поэтому, если ваш итератор уже создает ссылки, вы получите ссылку на ссылку, а если ваш итератор создает не ссылочные значения, вы получите ссылки на эти значения.

Разницу становится легче понять, если мы используем a Vec для обоих примеров:

 fn main() {
    let a = vec![0, 1, 2, 3];
    let a_iter = a.iter(); // iter() returns iterator over references
    let x: Vec<amp;i32> = a_iter.filter(|x: amp;amp;i32| **x > 1).collect();
    println!("{:?}", x);

    let b = vec![0, 1, 2, 3];
    let b_iter = a.into_iter(); // into_iter() returns iterator over values
    let y: Vec<i32> = b_iter.filter(|x: amp;i32| *x > 1).collect();
    println!("{:?}", y);
}
 

игровая площадка

Ответ №2:

Это потому, что в примере с массивом вы сначала вызываете .iter() для создания итератора, который заимствует массив и, следовательно, значения в нем; аргумент закрытия to filter получает заимствованную версию итератора Item , поэтому он снова заимствуется, что делает его a amp;amp;i32 .

В Range случае -case вы вызываете filter напрямую, поскольку a Range является итератором. Таким образом, итератор содержит собственные значения, и замыкание в filter заимствует это, что создает его тип amp;i32 .

Вы можете видеть, что если вы попытаетесь let y = b; после let b_iter = ... -line: Вы получите use of moved value -error, потому b что был использован итератором, который вы использовали в b.filter