Extracting data from a RefCell

I'm trying to find a way to extract data from a RefCell. Specifically, I have a RefCell that looks like this: Rc<RefCell<Vec<String>>> and I want my function to return the Vec<String>. After lots of experimentation, I'm getting nowhere. My latest idea is to use a loop to step through the elements of the vector contained in the RefCell, pushing each into a new Vec<String>, but I keep getting error messages that tell me I can't treat the RefCell like a regular vector. I know I'm likely on the wrong track, so could someone get me pointed in the right direction? Thanks.

Here is my latest experiment:

use std::cell::RefCell;
use std::rc::Rc;

fn main() {
    let newvec = rc_extract_data();
    println!("In main() newvec now contains   {:?} \n", newvec);
}

fn rc_extract_data() -> Vec<String> {
    let usevec: RefCell<Vec<String>> = RefCell::new(Vec::new());

    let newrc: Rc<RefCell<Vec<String>>> = Rc::new(usevec);
    println!("\n ---- newrc has been created ---- \n");
    {
        newrc.borrow_mut().push("cats".to_string());
        newrc.borrow_mut().push("dogs".to_string());
        newrc.borrow_mut().push("chickens".to_string());
    }
    println!("newrc now contains   {:?} \n", newrc);

    let mut retvec: Vec<String> = Vec::new();
    let mut i = 0;
    while i < newrc.len() {
        retvec.push(newrc[i]);
        i += 1;
    }
    println!("retvec now contains   {:?} \n", retvec);
    retvec
}
use std::{
    cell::RefCell,
    mem::take,
};

fn main() {
    let vec_cell = RefCell::new(vec![1, 2, 3]);
    assert_eq!(vec_cell.borrow().as_slice(), &[1, 2, 3]);
    let vec: Vec<i32> = take(&mut *vec_cell.borrow_mut());
    assert_eq!(vec.as_slice(), &[1, 2, 3]);
    assert_eq!(vec_cell.borrow().as_slice(), &[]);
}
1 Like

Or .clone() the vector if you don't want the copy in the RefCell to be altered.

Wow, @gretchenfrage , that's powerful! I hadn't seen that take() before. I can think of all kinds of wonderful uses for it. Anyway, I played around with it a bit, then incorporated it into the experiment I listed above, and it works well. I followed your example and didn't even have any glitches to work through. Thanks!

Next I'll need to incorporate it into my project. I'll come back here if I have any questions.

1 Like

:slight_smile: keep in mind that mem::take(&mut vec) is just equivalent to mem::replace(&mut vec, Vec::new()). Which is just equivalent to:

{
    let mut vec2 = Vec::new();
    mem::swap(&mut vec, &mut vec2);
    vec2
}

You are taking ownership of the vector in the RefCell (and by extension its heap allocation) and replacing it with an empty vec. There is an optimization where an empty vec constructed by Vec::new() will start out without having any heap allocation, but rather, just containing a null pointer and having a capacity of 0, which means that Vec::new() is a basically free operation. However, the new vec resulting from Vec::new() which you put in the cell when you take it will still have to create a new heap allocation the first time you actually insert an element into it.

1 Like

A dangling pointer, not a null pointer.

3 Likes

Oh nice.

1 Like

This topic was automatically closed 90 days after the last reply. We invite you to open a new topic if you have further questions or comments.