let shoes = vec![
Shoe {
size: 10,
style: String::from("sneaker"),
},
Shoe {
size: 13,
style: String::from("sandal"),
},
Shoe {
size: 10,
style: String::from("boot"),
},
];
let shoe_size = 10;
let filtered_shoes: Vec<&Shoe> = shoes.iter().filter(|s| s.size == shoe_size).collect();
let shoe_0: &Shoe = shoes.get(0).unwrap();
println!("address vec shoe {:p}", shoes);
println!("address filtered shoe {:p}", filtered_shoes);
println!("{:?}", filtered_shoes);
println!("{:?}", shoe_0);
Given collect fn following the filter operation, why is the return type Vec<&Shoe>
instead of Vec<Shoe>
.
Please note that into_iter
is not a possibility here.
In other languages like javascript, filter would copy from the original and would return new vector. Printing the address of those 2 vectors shows two different addresses.
The other was part how to make shoe_0
have the type of Shoe
instead of &Shoe
?
That's one of the selling points of Rust, it doesn't hide creating copies or otherwise managing the memory form you like JavaScript, a garbage collected language would. Instead, you have to explicitly instruct it to do so. For that you need a way to convert references to a shoe (&Shoe
) into owned Shoe
s, the most common being deriving Clone
for Shoe
and cloning the shoes:
#[derive(Clone)]
struct Shoe { /* … */ }
then you can use the iterator adapter .cloned()
to convert an Iterator<Item = &Shoe>
into an Iterator<Item = Shoe>
let filtered_shoes: Vec<Shoe> = shoes.iter().cloned().filter(|s| s.size == shoe_size).collect();
and similarly you can .clone()
a &Shoe
to turn it into a Shoe
:
let shoe_0: Shoe = shoes.get(0).unwrap().clone();