Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

What is the standard way to call a mutable method in a Rc-wrapped object?

Tags:

rust

In the following code, I am trying to change the value of a refcounted object by calling one of its methods:

use std::rc::Rc;

fn main() {
    let mut x = Rc::new(Thing { num: 50 });
    x.what_to_do_to_get_mut_thing().change_num(19); //what do i do here
}

pub struct Thing {
    pub num: u32,
}

impl Thing {
    pub fn change_num(&mut self, newnum: u32) {
        self.num = newnum;
    }
}

I am using the get_mut function to achieve this, but I don't know if this is a standard way to accomplish this.

if let Some(val) = Rc::get_mut(&mut x) {
    val.change_num(19);
}
like image 872
ZNackasha Avatar asked Oct 25 '18 16:10

ZNackasha


1 Answers

The documentation for Rc says:

See the module-level documentation for more details.

Which has this text:

This is difficult because Rc enforces memory safety by only giving out shared references to the value it wraps, and these don't allow direct mutation. We need to wrap the part of the value we wish to mutate in a RefCell, which provides interior mutability: a method to achieve mutability through a shared reference. RefCell enforces Rust's borrowing rules at runtime.

It then demonstrates how to use it.


If you didn't read the API documentation, you might have instead chosen to read the entire chapter about Rc in The Rust Programming Language. It has this to say:

Via immutable references, Rc<T> allows you to share data between multiple parts of your program for reading only. If Rc<T> allowed you to have multiple mutable references too, you might violate one of the borrowing rules discussed in Chapter 4: multiple mutable borrows to the same place can cause data races and inconsistencies. But being able to mutate data is very useful! In the next section, we’ll discuss the interior mutability pattern and the RefCell<T> type that you can use in conjunction with an Rc<T> to work with this immutability restriction.


Applying this new knowledge to your code:

use std::{cell::RefCell, rc::Rc};

fn main() {
    let x = Rc::new(RefCell::new(Thing { num: 50 }));
    x.borrow_mut().change_num(19);
}

See also:

  • How do I share a mutable object between threads using Arc?
  • Situations where Cell or RefCell is the best choice
  • What is the difference between Rc<RefCell<T>> and RefCell<Rc<T>>?
  • When I can use either Cell or RefCell, which should I choose?
  • Need holistic explanation about Rust's cell and reference counted types

I am using the get_mut function

It's very unlikely that you want to use this.

See also:

  • Explain the behavior of *Rc::make_mut and why it differs compared to Mutex
like image 91
Shepmaster Avatar answered Oct 25 '22 19:10

Shepmaster