Returning a reference to a struct in a refcell


#1

Hi, i’m currently playing around in rust in a pet project trying to get some data out of a postgres db.

So i have this code here:

 #[derive(Default)]
 struct ObjectCache {
     pub db_objects: Option<Vec<ObjectConfig>>,
 }
pub struct Setup {
    db: Arc<Db>,
    cache: RefCell<ObjectCache>,
}

impl Setup {
    pub fn new(db: Arc<Db>) -> Setup {
        Setup {
            db: db,
            cache: Default::default(),
        }
}

pub fn list_db_objects(&self) -> Result<Vec<(String, u32)>, String> {
    let objects = self.db.get_selected_objects(-1).unwrap();
    self.cache.borrow_mut().db_objects = Some(objects);
    let result = self.cache
        .borrow()
        .db_objects
        .as_ref()
        .unwrap()
        .iter()
        .map(|obj| (obj.name.clone(), obj.count))
        .collect();
    Ok(result)
}
}

This works fine, the only issue i have now is that I have to clone anything that i want to return from list_db_objects:
.map(|obj| (obj.name.clone(), obj.count))

is it possible to change the code to somehow just return a reference like this:
.map(|obj| (&obj.name, obj.count))

Thanks


#2

It’s not possible because that could break RefCell protection (ie dynamic borrow checking). You could invert the API a bit - have the caller pass a closure that receives a Vec<(String, u32)> and call it with the results. Alternatively, you could return the object in the Ref wrapper although that leaks the fact you’re using a RefCell.


#3

ah thanks, didn’t think of that before, but using a closure is actually a good idea. It also avoids having to iterate twice over the same Vec:
let mut i:u32 = 0; self.cache .borrow() .db_objects .as_ref() .unwrap() .iter() .map(|obj| { i += 1; (i,&obj.name, obj.count) }) .inspect(print_func) .count();
with print_func being:
let print_func = |obj: &(u32, &String, u32)| { println!("{}.\t{}\t\t\t{}", obj.0, obj.1, obj.2); };