Filtering and Editing a Vector full of custom structs based on a struct variable

Hello Rust Community,

I've hit a wall when it comes to editing elements of a vector that is full of custom structs.

Problem: I would like to allow users to filter the records (a struct in this case) using the supplied id field, rather than using a raw index to get a mutable reference to the vector element.

  • this is because I want a user to be able to edit a record after selecting one via its' ID, since I feel like index is simply too brittle to rely on.

However, if you run this code within the playground it throws a "use of moved value" error.

Now I get why this is happening, because the selection function is moving the element of the vector, but I don't know how to get around the borrow checker on this one. how would I go about filtering a struct by an element's field value, and using the resulting record to mutate the struct within via the defined methods?

  • the string is there because we could imagine a record would need a name, thus precluding an easy "just derive copy" answer.

Thank you in advance for your time and expertise.

use std::error::Error;
use std::io::{Error as OtherError, ErrorKind};

struct RecordList{
    records: Vec<TestRecord>
}

struct TestRecord{
    id: usize,
    test_attribute: bool,
    name: String,
}

impl RecordList{
    fn select_record_by_id(self, id: usize)-> Result<TestRecord, Box<dyn Error>>{
        let search_record = self.records.into_iter()
        .find(|record|record.id == id);
        match search_record {
            Some (ref _record) => return Ok(search_record.unwrap()),
            None => return Err(Box::new(OtherError::new(ErrorKind::Other, "No Record with given id")))
        }
    }
}

impl TestRecord {
    fn flip_test_attribute (mut self) {
        self.test_attribute = true;
    }
}

fn main(){
    let record_vec = RecordList{
        records: vec![TestRecord{
        id: 1,
        test_attribute: false,
        name: "test".to_string()
    }]};
    record_vec.select_record_by_id(1).unwrap().flip_test_attribute();
    println!("{}",record_vec.select_record_by_id(1).unwrap().test_attribute);
}

Looking at your code, it seems like you should be using mutable references here.

impl RecordList{
    fn select_record_by_id(&mut self, id: usize)-> Result<&mut TestRecord, Box<dyn Error>>{
        let search_record = self.records.iter_mut()
            .find(|record| record.id == id);
        match search_record {
            Some(record) => Ok(record),
            None => Err(Box::new(OtherError::new(ErrorKind::Other, "No Record with given id")))
        }
    }
}

impl TestRecord {
    fn flip_test_attribute(&mut self) {
        self.test_attribute = true;
    }
}

Note how both methods were changed from taking self by value (no ampersand) to taking self by mutable borrow (ampersand with mut after it). Note also how select_record_by_id returns a mutable reference.

1 Like