1

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>>>?

Kitsu
  • 3,166
  • 14
  • 28
ANimator120
  • 2,556
  • 1
  • 20
  • 52
  • 3
    Why would `count_strings` take `strings: Vec` instead of `strings: &[String]` or something even more generic, since requiring `String` is also pretty heavy. This is only a problem because `count_strings` explicitly says it needs to own a whole vector with strings, which is not at all needed it looks like. – loganfsmyth Jun 10 '21 at 23:18
  • 1
    See also https://stackoverflow.com/questions/40006219/why-is-it-discouraged-to-accept-a-reference-to-a-string-string-vec-vec-o – Jmb Jun 11 '21 at 06:24

1 Answers1

1

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![]);
Kitsu
  • 3,166
  • 14
  • 28