解释* Rc :: make_mut的行为及其与Mutex

时间:2017-05-16 22:24:03

标签: rust

我需要在几个使用闭包作为参数的函数之间传递资源。在这些数据中,数据得到了处理,但它寻找的变量将反映在变量中。

我认为首先要使用Rc。我之前使用Arc来处理不同线程之间的数据,但由于这些函数不在不同的线程中运行,我选择了Rc

我所拥有的最简化的代码,以表达我的疑虑:

RefCell的使用是因为我可能必须看到这种语法不能像我预期的那样工作:

*Rc::make_mut(&mut rc_pref_temp)...
use std::sync::Arc;
use std::rc::Rc;
use std::sync::Mutex;
use std::cell::RefCell;
use std::cell::Cell;

fn main() {
    test2();
    println!("---");
    test();
}

#[derive(Debug, Clone)]
struct Prefe {
    name_test: RefCell<u64>,
}

impl Prefe {
    fn new() -> Prefe {
        Prefe {
            name_test: RefCell::new(3 as u64),
        }
    }
}

fn test2(){
    let mut prefe: Prefe = Prefe::new();

    let mut rc_pref = Rc::new(Mutex::new(prefe));

    println!("rc_pref Mutex: {:?}", rc_pref.lock().unwrap().name_test);

    let mut rc_pref_temp = rc_pref.clone();

    *rc_pref_temp.lock().unwrap().name_test.get_mut() += 1;

    println!("rc_pref_clone Mutex: {:?}", rc_pref_temp.lock().unwrap().name_test);

    *rc_pref_temp.lock().unwrap().name_test.get_mut() += 1;

    println!("rc_pref_clone Mutex: {:?}", rc_pref_temp.lock().unwrap().name_test);

    println!("rc_pref Mutex: {:?}", rc_pref.lock().unwrap().name_test);
}

fn test(){
    let mut prefe: Prefe = Prefe::new();

    let mut rc_pref = Rc::new(prefe);

    println!("rc_pref: {:?}", rc_pref.name_test);

    let mut rc_pref_temp = rc_pref.clone();

    *((*Rc::make_mut(&mut rc_pref_temp)).name_test).get_mut() += 1;

    println!("rc_pref_clone: {:?}", rc_pref_temp.name_test);

    *((*Rc::make_mut(&mut rc_pref_temp)).name_test).get_mut() += 1;

    println!("rc_pref_clone: {:?}", rc_pref_temp.name_test);

    println!("rc_pref: {:?}", rc_pref.name_test);
}

代码被简化,使用它的场景完全不同。我注意到这一点,以避免像#34;你可以为函数&#34;提供一个值,因为我感兴趣的是知道为什么暴露的案例以这种方式工作。

标准输出:

rc_pref       Mutex  : RefCell { value: 3 }
rc_pref_clone Mutex  : RefCell { value: 4 }
rc_pref_clone Mutex  : RefCell { value: 5 }
rc_pref       Mutex  : RefCell { value: 5 }
---
rc_pref              : RefCell { value: 3 }
rc_pref_clone        : RefCell { value: 4 }
rc_pref_clone        : RefCell { value: 5 }
rc_pref              : RefCell { value: 3 }

关于test()

我是Rust的新手,所以我不知道这种疯狂的语法是否正确。

*((*Rc::make_mut(&mut rc_pref_temp)).name_test).get_mut() += 1;

运行test()时,您可以看到之前的语法有效,因为它会增加值,但这种增加不会影响克隆。我希望通过使用*Rc::make_mut(& mut rc_pref_temp)...,共享引用的克隆将反映相同的值。

  • 如果Rc引用了同一个对象,为什么对象的更改不适用于其他克隆?为什么这样工作?我做错了吗?

注意:我使用RefCell因为在某些测试中我认为我可能有事情要做。

关于test2()

我使用Mutex使用Rc按预期工作,但我不知道这是否正确。我对MutexArc的工作原理有一些想法,但在使用此语法之后:

*Rc::make_mut(&mut rc_pref_temp)...

Mutex中使用test2(),我想知道Mutex是否不仅负责更改数据,而且负责反映所有克隆的数据引用。

共享引用实际上指向同一个对象吗?我想他们会这么做,但是如果没有使用Mutex而没有反映出更改的上述代码,我有一些疑问。

1 个答案:

答案 0 :(得分:6)

在使用之前,您需要阅读并理解您使用的功能的文档。 Rc::make_mut says,强调我的:

  

对给定的Rc进行可变引用。

     

如果有其他RcWeak指针指向相同的值,那么   make_mut将在内部值上调用clone以确保唯一   所有权。这也称为写在克隆。

     

另请参阅get_mut,它将失败而不是克隆。

您有多个Rc指针,因为您调用了rc_pref.clone() 。因此,当您调用make_mut时,内部值将被克隆,Rc指针现在将彼此解除关联:

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
}

Mutex的版本有效,因为它完全不同。你不是在调用一个克隆内部值的函数。当然,当你没有线程时使用Mutex是没有意义的。 Mutex的单线程等价物是...... RefCell

老实说,我不知道你是怎么找到的Rc::make_mut;我以前从未听过module documentation for cell没有提到它,module documentation for rc也没有提到它。

我强烈建议您退后一步,重新阅读文档。 second edition of The Rust Programming Language有一个chapter on smart pointers,包括RcRefCell。阅读rccell的模块级文档。

这是您的代码应该是什么样子。请注意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
}