具有多个强引用并允许可变性的正确智能指针是什么? [英] What is the right smart pointer to have multiple strong references and allow mutability?

查看:44
本文介绍了具有多个强引用并允许可变性的正确智能指针是什么?的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我想在堆上有一个结构,有两个引用;一个给我,另一个来自关闭.注意代码是针对单线程情况的:

I want to have a structure on the heap with two references; one for me and another from a closure. Note that the code is for the single-threaded case:

use std::rc::Rc;

#[derive(Debug)]
struct Foo {
    val: u32,
}
impl Foo {
    fn set_val(&mut self, val: u32) {
        self.val = val;
    }
}
impl Drop for Foo {
    fn drop(&mut self) {
        println!("we drop {:?}", self);
    }
}

fn need_callback(mut cb: Box<FnMut(u32)>) {
    cb(17);
}

fn create() -> Rc<Foo> {
    let rc = Rc::new(Foo { val: 5 });
    let weak_rc = Rc::downgrade(&rc);
    need_callback(Box::new(move |x| {
        if let Some(mut rc) = weak_rc.upgrade() {
            if let Some(foo) = Rc::get_mut(&mut rc) {
                foo.set_val(x);
            }
        }
    }));
    rc
}

fn main() {
    create();
}

在实际代码中,need_callback 将回调保存到某个地方,但在此之前可能会像 need_callback 那样调用 cb.

In the real code, need_callback saves the callback to some place, but before that may call cb as need_callback does.

代码显示std::rc::Rc不适合这个任务,因为foo.set_val(x)从未被调用;我有两个强引用,在这种情况下 Rc::get_mut 给出了 None.

The code shows that std::rc::Rc is not suitable for this task because foo.set_val(x) is never called; I have two strong references and Rc::get_mut gives None in this case.

我应该使用什么带有引用计数的智能指针而不是 std::rc::Rc 来调用 foo.set_val?也许有可能修复我的代码并仍然使用 std::rc::Rc?

What smart pointer with reference counting should I use instead of std::rc::Rc to make it possible to call foo.set_val? Maybe it is possible to fix my code and still use std::rc::Rc?

经过一些思考,我需要像 std::rc::Rc 这样的东西,但是弱引用应该可以防止丢失.我可以有两个弱引用,并在需要可变性时将它们升级为强引用.

After some thinking, I need something like std::rc::Rc, but weak references should prevent dropping. I can have two weak references and upgrade them to strong when I need mutability.

因为是单线程程序,我一次只会有强引用,所以一切都会按预期进行.

Because it is a singled-threaded program, I will have only strong reference at a time, so everything will work as expected.

推荐答案

Rc(和它的多线程对应物 Arc)只关心自己的所有权.现在不是单一所有者,而是在运行时跟踪的共同所有权.

Rc (and its multithreaded counterpart Arc) only concern themselves with ownership. Instead of a single owner, there is now joint ownership, tracked at runtime.

可变性是一个不同的概念,虽然与所有权密切相关:如果你拥有一个值,那么你就有能力改变它.这就是为什么 Rc::get_mut 仅在有一个强引用时才起作用的原因 - 这与说只有一个所有者一样.

Mutability is a different concept, although closely related to ownership: if you own a value, then you have the ability to mutate it. This is why Rc::get_mut only works when there is a single strong reference - it's the same as saying there is a single owner.

如果您需要以与程序结构不匹配的方式划分可变性的能力,您可以使用诸如 CellRefCell 用于单线程程序:

If you need the ability to divide mutability in a way that doesn't match the structure of the program, you can use tools like Cell or RefCell for single-threaded programs:

use std::cell::RefCell;

fn create() -> Rc<RefCell<Foo>> {
    let rc = Rc::new(RefCell::new(Foo { val: 5 }));
    let weak_rc = Rc::downgrade(&rc);
    need_callback(move |x| {
        if let Some(rc) = weak_rc.upgrade() {
            rc.borrow_mut().set_val(x);
        }
    });
    rc
}

或者 MutexRwLock多线程上下文中的原子类型:

use std::sync::Mutex;

fn create() -> Rc<Mutex<Foo>> {
    let rc = Rc::new(Mutex::new(Foo { val: 5 }));
    let weak_rc = Rc::downgrade(&rc);
    need_callback(move |x| {
        if let Some(rc) = weak_rc.upgrade() {
            if let Ok(mut foo) = rc.try_lock() {
                foo.set_val(x);
            }
        }
    });
    rc
}

这些工具都推迟了对运行时只有一个可变引用的检查,而不是编译时.

These tools all defer the check that there is only a single mutable reference to runtime, instead of compile time.

这篇关于具有多个强引用并允许可变性的正确智能指针是什么?的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

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