ANimator120
ANimator120

Reputation: 3401

Get a Vector of Strings from a Rc<RefCell<Vec<String>>> in Rust

I have a function that takes in a Vec<String> value. I want to use this function on values contained inside my_ref, so I need to extract a Vec<String> out of a Rc<RefCell<Vec<String>>>.

I thought I could do this by dereferencing a borrow of my my_ref, just like I would for a Rc<RefCell<f32>>> or Rc<RefCell<i32>>> value:

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

fn main() {
    let my_ref = Rc::from(RefCell::from(vec![
        "Hello 1".to_string(),
        "Hello 2".to_string(),
    ]));
    let my_strings: Vec<String> = *my_ref.borrow();
    let count = count_strings(my_strings);
}

fn count_strings(strings: Vec<String>) -> usize {
    strings.len()
}

But doing so results in a dereferencing error:

error[E0507]: cannot move out of dereference of `Ref<'_, Vec<String>>`
cannot move out of dereference of `Ref<'_, Vec<String>>`
move occurs because value has type `Vec<String>`, which does not implement the `Copy` trait

So then, how do I properly extract a Vec<String> from a Rc<RefCell<Vec<String>>>?

Upvotes: 1

Views: 642

Answers (1)

Kitsu
Kitsu

Reputation: 3435

RefCell::borrow returns a reference, not an owned value, that's why you having such an error. I can name two different solution for that problem.

Promoting Rc to exclusively-owned type

Rc::try_unwrap is able to check, whether there's other references to the data. If it's the only one, it can be safely converted to the inner type. Then, an owned RefCell can be converted into its inner via into_inner function.

let my_ref = Rc::from(RefCell::new(vec![..]));
let inner: Vec<_> = Rc::try_unwrap(my_ref).expect("I hereby claim that my_ref is exclusively owned").into_inner();

Replacing inner value

If for some reason you want to grab inner value that is already referenced, you may consider replacing it. Note, that you need to create a appropriate value for the type (i.e. with trait Default). Here's the example:

let my_ref = Rc::from(RefCell::new(vec![..]));
let inner: Vec<_> = my_ref.borrow_mut().take();
// or
let inner: Vec<_> = my_ref.borrow_mut().replace(vec![]);

Upvotes: 2

Related Questions