解释 *Rc::make_mut 的行为以及它与 Mutex 相比的不同之处 [英] Explain the behavior of *Rc::make_mut and why it differs compared to Mutex

查看:41
本文介绍了解释 *Rc::make_mut 的行为以及它与 Mutex 相比的不同之处的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我需要在几个使用闭包作为参数的函数之间传递一个资源.并且在这些数据中处理了数据,但它寻找对变量实现的更改将反映在其余部分中.

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 realized to a variable will be reflected in the rest.

我首先想到的是使用Rc.我以前使用 Arc 来处理不同线程之间的数据,但由于这些函数不在不同线程中运行,所以我选择了 Rc.

The first thing I thought was to use Rc. I had previously used Arc to handle the data between different threads, but since these functions aren't running in different threads I chose Rc instead.

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

The most simplified code that I have, to show my doubts:

使用 RefCell 是因为也许我不得不看到这个语法不会像我预期的那样工作:

The use of RefCell was because maybe I had to see that this syntax will not work as I expected:

*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);
}

代码简化了,使用场景完全不同.我注意到这一点是为了避免诸如你可以为函数赋予价值"之类的评论,因为我感兴趣的是知道为什么这些案例会以这种方式工作.

The code is simplified, the scenario where it is used is totally different. I note this to avoid comments like "you can lend a value to the function", because what interests me is to know why the cases exposed work in this way.

标准输出:

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 的新手,所以我不知道这种疯狂的语法是否正确.

About test()

I'm new to Rust so I don't know if this crazy syntax is the right way.

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

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

When running test() you can see that the previous syntax works, because it increases the value, but this increase does not affect the clones. I expected that with the use of *Rc::make_mut(& mut rc_pref_temp)... that the clones of a shared reference would reflect the same values.

  • 如果 Rc 引用了同一个对象,为什么对一个对象的更改不适用于其余的克隆?为什么这样工作?我做错了什么吗?
  • If Rc has references to the same object, why do the changes to an object not apply to the rest of the clones? Why does this work this way? Am I doing something wrong?

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

Note: I use RefCell because in some tests I thought that maybe I had something to do.

我使用 MutexRc 让它按预期工作,但我不知道这是否是正确的方法.我对 MutexArc 的工作原理有一些想法,但在使用以下语法后:

I've got it working as expected using Mutex with Rc, but I do not know if this is the correct way. I have some ideas of how Mutex and Arc works, but after using this syntax:

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

test2()中使用了Mutex,不知道Mutex是不是不仅负责修改里面的数据,还负责一个负责反映所有克隆引用的变化.

With the use of Mutex in test2(), I wonder if Mutex is not only responsible for changing the data in but also the one in charge of reflecting the changes in all the cloned references.

共享引用实际上指向同一个对象吗?我想他们这样做,但是对于上面的代码,如果不使用 Mutex 就不会反映更改,我有一些疑问.

Do the shared references actually point to the same object? I want to think they do, but with the above code where the changes are not reflected without the use of Mutex, I have some doubts.

推荐答案

在使用之前,您需要阅读并理解所用函数的文档.Rc::make_mut,强调我的:

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

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

Makes a mutable reference into the given Rc.

如果还有其他 RcWeak 指针指向相同的值,则make_mut 将对内部值调用 clone 以确保唯一所有权.这也称为写时克隆.

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.

另见 get_mut,它会失败而不是克隆.

See also get_mut, which will fail rather than cloning.

您有多个 Rc 指针因为您调用了 rc_pref.clone().因此,当您调用 make_mut 时,内部值将被克隆并且 Rc 指针现在将彼此分离:

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
}

带有 Mutex 的版本有效,因为它完全不同.您不再调用克隆内部值的函数.当然,在没有线程的情况下使用 Mutex 是没有意义的.Mutex 的单线程等价物是... RefCell!

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!

老实说我不知道​​你是怎么找到Rc::make_mut的;我以前从未听说过.cell 的模块文档没有提及它,模块文档rc.

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.

我强烈建议您退后一步,重新阅读文档.第二版 The Rust Programming Language 有一个 智能指针章节,包括 RcRefCell.阅读 rc 的模块级文档和 cell 也是如此.

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.

您的代码应该如下所示.注意 borrow_mut<的用法/a>.

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
}

这篇关于解释 *Rc::make_mut 的行为以及它与 Mutex 相比的不同之处的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
相关文章
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆