Reputation: 221
I want to change the value of a specific attribute of a vector of objects.
my code and logic are as follows:
let mut person_found: Vec<Person> = persons.clone().into_iter().filter(|x| x.id == "3")
.map(|x| x.name = "Carlos".to_string()).collect();
println!("original: {:?}", &persons);
println!("modified person: {:?}", &person_found);
But it gives me the following error and I can't understand it well.
error[E0277]: a value of type `Vec<Person>` cannot be built from an iterator over elements of type `()`
--> src\main.rs:17:45
|
17 | .map(|x| x.name = "Carlos".to_string()).collect();
| ^^^^^^^ value of type `Vec<Person>` cannot be built from `std::iter::Iterator<Item=()>`
|
= help: the trait `FromIterator<()>` is not implemented for `Vec<Person>`
Upvotes: 2
Views: 1825
Reputation: 42678
You are returning nothing in your map expr line. You can handle with filter_map
though:
let mut person_found: Vec<Person> = persons
.iter()
.filter_map(|p|
(p.id == 3).then_some(Person {
name: String::from("Carlos"),
..p.clone()}))
.collect();
Upvotes: 3
Reputation: 26157
The result of an assignment is ()
(the unit value). So if you do y = (x = 123);
then x
is assigned 123
and y
is assigned ()
.
The Rust Reference has a short sentence stating:
An assignment expression always produces the unit value.
– Assignment expressions - Operator expressions - The Rust Reference
You need to change so it explicitly returns x
on the next line, for that to work. If you want to mutate x
then you also need to change |x|
to |mut x|
.
let person_found: Vec<Person> = persons
.clone()
.into_iter()
.filter(|x| x.id == "3")
.map(|mut x| {
x.name = "Carlos".to_string();
x
})
.collect();
Alternatively, instead of cloning the whole persons
Vec
upfront, I'd instead use cloned()
after filter()
or clone()
in map()
, i.e. only when needed.
let person_found: Vec<Person> = persons
.iter()
.filter(|x| x.id == "3")
.cloned()
.map(|mut x| {
x.name = "Carlos".to_string();
x
})
.collect();
Upvotes: 5