Reputation: 109
I have a similar issue as this one How can I change fields of elements in vectors in Rust?. Where I can't just seem to get it working. I have been adding '&' and 'mut' all over the place, but I am out of a clue..
#[derive(Debug)]
struct Character{
name: String,
}
struct Characters {
records : Vec<Character>
}
impl Characters {
fn set_value(self, value : String) {
for record in self.records {
record.name = value;
}
}
}
fn test() {
let hobbits = vec![
Character{name:String::from("Sam")},
Character{name:String::from("Merry")},
Character{name:String::from("Pepper")},
];
let chars = Characters {
records : hobbits
};
// Set all names to "Halfling
chars.set_value("Halfling".to_string());
}
This does not compile for several reasons, but my main thing is; I want to modify a variable of a struct inside another struct vector variable impl. Trying all sorts of things but am unable to get it to work.
Upvotes: 0
Views: 864
Reputation: 23244
First thing first, since you want set_value
to change the value of a field, it needs to take &mut self
:
impl Characters {
fn set_value(&mut self, value : String) {
for record in self.records {
record.name = value;
}
}
}
This still has several errors, the first of which is:
error[E0507]: cannot move out of `self.records` which is behind a mutable reference
--> src/lib.rs:12:23
|
12 | for record in self.records {
| ^^^^^^^^^^^^
| |
| `self.records` moved due to this implicit call to `.into_iter()`
| move occurs because `self.records` has type `Vec<Character>`, which does not implement the `Copy` trait
|
note: this function takes ownership of the receiver `self`, which moves `self.records`
help: consider iterating over a slice of the `Vec<Character>`'s content to avoid moving into the `for` loop
|
12 | for record in &self.records {
| +
Following the compiler suggestion, we get:
impl Characters {
fn set_value(&mut self, value : String) {
for record in &self.records {
record.name = value;
}
}
}
giving this error:
error[E0594]: cannot assign to `record.name`, which is behind a `&` reference
--> src/lib.rs:13:13
|
12 | for record in &self.records {
| ------------- this iterator yields `&` references
13 | record.name = value;
| ^^^^^^^^^^^ `record` is a `&` reference, so the data it refers to cannot be written
Here the compiler doesn't give a straight solution, but it suggests that the issue is that record
is not mutable. Unfortunately simply using for mut record
doesn't change anything. The solution is actually the same as the first change we made: since we want to modify self.records
, we need to borrow it mutably: for record in &mut self.records
.
While we're here, let's look at the second error:
error[E0382]: use of moved value: `value`
--> src/lib.rs:13:27
|
11 | fn set_value(&mut self, value : String) {
| ----- move occurs because `value` has type `String`, which does not implement the `Copy` trait
12 | for record in &self.records {
13 | record.name = value;
| ^^^^^ value moved here, in previous iteration of loop
This makes sense: once we've moved value
in the first record
, we don't have it anymore so we can't put it in the others. We can ask the compiler for more explanations on the error with rustc --explain E0382
and we get the solution in the third example:
Sometimes we don't want a reference, but a duplicate. All types marked
Clone
can be duplicated by calling.clone()
.
If we clone value
, we get:
impl Characters {
fn set_value(&mut self, value : String) {
for record in &mut self.records {
record.name = value.clone();
}
}
}
And now this function compiles. There remains only one error in another part of the code:
error[E0596]: cannot borrow `chars` as mutable, as it is not declared as mutable
--> src/lib.rs:30:5
|
25 | let chars = Characters {
| ----- help: consider changing this to be mutable: `mut chars`
...
30 | chars.set_value("Halfling".to_string());
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ cannot borrow as mutable
Following the compiler suggestion, we write let mut chars
and we get the working solution:
#[derive(Debug)]
struct Character{
name: String,
}
struct Characters {
records : Vec<Character>
}
impl Characters {
fn set_value(&mut self, value : String) {
for record in &mut self.records {
record.name = value.clone();
}
}
}
fn test() {
let hobbits = vec![
Character{name:String::from("Sam")},
Character{name:String::from("Merry")},
Character{name:String::from("Pepper")},
];
let mut chars = Characters {
records : hobbits
};
// Set all names to "Halfling
chars.set_value("Halfling".to_string());
}
Upvotes: 1