#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