// code snippet
let v2: RefCell<Vec<RefCell<String>>> = RefCell::new(vec![
RefCell::new("c".to_string()),
RefCell::new("d".to_string()),
]);
// note Rc is the difference from v2 above.
let mut v3: Rc<RefCell<Vec<RefCell<String>>>> = Rc::new(RefCell::new(vec![
RefCell::new("c".to_string()),
RefCell::new("d".to_string()),
]));
// works
*v2.borrow_mut()[1].borrow_mut() = "Z".to_string();
v2.borrow_mut().push(RefCell::new("W".to_string()));
println!("v3[1]:{}", v3.borrow()[1].borrow());
println!("v3[1]:{}", v3.borrow()[1].borrow_mut());
*v3.borrow()[1].borrow_mut() = "ZZ".to_string(); // individual vector element mutation works too
println!("v3[1]:{}", v3.borrow()[1].borrow_mut());
// this like does not compile:
// +++++ ******
v3.borrow_mut().push(RefCell::new("Y".to_string())); // compile error
// ----- ******
// compiler error:
// no method named `push` found for mutable reference `&mut std::rc::Rc<std::cell::RefCell<std::vec::Vec<std::cell::RefCell<std::string::String>>>>` in the current scope
// method not found in `&mut Rc<RefCell<Vec<RefCell<String>>>>`
Hello
I am just trying to get my Rc and RefCell understanding.
In above code the variables v2 and v3 differ in v3 being Rc.
I believe Rc<RefCell.... still wont allow me to mutate the Vec (push/pop methods).
I am able to mutable individual vector elements in v2 and v3 and push() new elements for v2. But since v3 is protected by Rc and despite of RefCell I am still not able to push() or pop() the vector even though I am still allowed to modify individual elements of vector.
I am trying to understand if there is a syntax to allow me to use push()/pop() for v3 given I have it wrapped in Rc.
Are you importing the Borrow and/or BorrowMut traits? Those can interefere with Rc<RefCell<_>> because they are implemented for all types. Try removing the imports.
Types can be imported without any implicit problems (the only problem is the direct name clash, and it is explicitly called out when it arises). Problems can arise when you import traits.
This particular situation is a design misstep in std. They shouldn't have used the same names for RefCell's borrowing and the Borrow/BorrowMut traits methods. Especially because the traits are implemented for everything -- that means that if you happen to call .borrow or .borrow_mut on anything that doesn't have inherent methods with that name, the compiler will suggest you import them. But as this thread shows, if you do that and are also using RefCell, sadness will probably result.
Additionally the only time you typically need those traits is if you need to repeat the bounds on keyed collections like HashMap and BTreeMap (or if you're implementing them yourself). So my advice is: avoid importing them when possible; for example if you need them in bounds only, just write out some path to the trait instead of importing the trait.
where Q: std::borrow::Borrow<K>,
But particularly if you're also using RefCell.
Diagnostics and documentation could definitely be improved here.
The reason the code works without the imports is that method resolution will eventually find the RefCell inherent method via the auto-derefing resolution algorithm. And the reason the code doesn't work with the imports is that it finds the trait implementation for Rc<_> before it gets around to the auto-deref portion of the algorithm that considers RefCell (since like everything else, Rc<_> implements the trait).
And the main way to spot the problem is just experience: you called borrow_mut but didn't get a RefMut in the error; instead the compiler was still looking for push at the outer Rc level.