Explain the behavior of *Rc::make_mut and why it differs compared to Mutex

前端 未结 1 1721
你的背包
你的背包 2021-01-21 01:16

I needed to pass a resource between several functions which use a closure as an argument. And within these the data was handled, but it looked for that the changes that were rea

相关标签:
1条回答
  • 2021-01-21 01:28

    You need to read and understand the documentation for functions you use before you use them. Rc::make_mut says, emphasis mine:

    Makes a mutable reference into the given Rc.

    If there are other Rc or Weak pointers to the same value, then make_mut will invoke clone on the inner value to ensure unique ownership. This is also referred to as clone-on-write.

    See also get_mut, which will fail rather than cloning.

    You have multiple Rc pointers because you called rc_pref.clone(). Thus, when you call make_mut, the inner value will be cloned and the Rc pointers will now be disassociated from each other:

    use std::rc::Rc;
    
    fn main() {
        let counter = Rc::new(100);
        let mut counter_clone = counter.clone();
        println!("{}", Rc::strong_count(&counter));       // 2
        println!("{}", Rc::strong_count(&counter_clone)); // 2
    
        *Rc::make_mut(&mut counter_clone) += 50;
        println!("{}", Rc::strong_count(&counter));       // 1
        println!("{}", Rc::strong_count(&counter_clone)); // 1
    
        println!("{}", counter);       // 100
        println!("{}", counter_clone); // 150
    }
    

    The version with the Mutex works because it's completely different. You aren't calling a function which clones the inner value anymore. Of course, it doesn't make sense to use a Mutex when you don't have threads. The single-threaded equivalent of a Mutex is... RefCell!


    I honestly don't know how you found Rc::make_mut; I've never even heard of it before. The module documentation for cell doesn't mention it, nor does the module documentation for rc.

    I'd highly encourage you to take a step back and re-read through the documentation. The second edition of The Rust Programming Language has a chapter on smart pointers, including Rc and RefCell. Read the module-level documentation for rc and cell as well.

    Here's what your code should look like. Note the usage of borrow_mut.

    fn main() {
        let prefe = Rc::new(Prefe::new());    
        println!("prefe: {:?}", prefe.name_test);             // 3
    
        let prefe_clone = prefe.clone();
        *prefe_clone.name_test.borrow_mut() += 1;
        println!("prefe_clone: {:?}", prefe_clone.name_test); // 4
    
        *prefe_clone.name_test.borrow_mut() += 1;
        println!("prefe_clone: {:?}", prefe_clone.name_test); // 5
        println!("prefe: {:?}", prefe.name_test);             // 5
    }
    
    0 讨论(0)
提交回复
热议问题