我有这样一个场景:Rust Playground

  • 我有一个 struct Container,它有一个保护多个成员的锁.我不想每个会员都有卢旺达锁.
  • 我想获得这个锁,然后调用另一个函数complex_mutation,该函数执行一些复杂的逻辑并改变这个 struct .
  • 问题是,锁的RAII保护_guard获取一个引用,然后调用另一个传递&mut self的函数complex_mutation会导致多个不可变+可变的引用.
  • 在创建另一个可变引用之前,我不能放弃保护,因为这就是这里提供同步的原因.
  • 如果我可以内联从complex_mutation开始的所有内容,这将会起作用,但对于现实世界的场景来说太难看了.

这是C++中的一种常见模式.我如何在Rust 中解决这个问题?

推荐答案

你似乎对几件事感到困惑.让我试着澄清一下.

  • 铁 rust 中的锁保护锁中包含的数据.在这种情况下,您是在保护(),这是没有意义的.
  • 如果你拿的是&mut self,那么锁对你没有帮助.锁是允许您从共享引用(&)获得独占引用(&mut)的众多机制之一.从共享引用开始写入值的能力称为"内部可变性",它由RwLock实现,也由MutexRefCell等实现.如果你已经从独占引用开始,内部可变性是多余的.

这样一来,您要做的就是将类型中的数据放入锁中.您可以使用元组来实现这一点,但更好的方法是使用私有的"内部"类型,如下所示:

struct Container {
    lock: RwLock<ContainerInner>,
}

struct ContainerInner {
    pub data1: u32,
    pub data2: u32,
}

现在,你想拿&self英镑来代替.

如果您有需要对ContainerInner中的数据进行操作的方法,因为您从多个位置调用它们,则可以简单地将它们放在ContainerInner中,如下所示:

impl Container {
    pub fn update_date(&self, val1: u32, val2: u32) {
        self.lock.write().unwrap().complex_mutation(val1, val2);
    }
}

impl ContainerInner {
    fn complex_mutation(&mut self, val1: u32, val2: u32) {
        self.data1 = val1;
        self.data2 = val2;
    }
}

请注意,如果您有&mut self,那么您实际上不需要锁定;如果您有&mut到锁without locking,则RwLock::get_mut()允许您获得内部值的&mut,因为锁有&mut是静态的,即该值不是共享的.

如果它在概念上对你有帮助,&&mut的工作原理分别类似于RwLock的S read()write()--你可以有多个&,也可以有一个&mut,如果你有&mut,你就不能有&.与运行时锁不同,Rust编译器会在编译时判断这些锁是否被正确使用,这意味着不需要运行时判断或锁.

因此,您可以添加如下所示的方法:

impl Container {
    pub fn update_date_mut(&mut self, val1: u32, val2: u32) {
        self.lock.get_mut().unwrap().complex_mutation(val1, val2);
    }
}

这与其他方法完全相同,不同之处在于我们使用&mut self,它允许我们使用get_mut()代替write(),从而绕过锁.编译器不会让您调用此方法,除非它能证明该值不是共享值,因此,如果编译器允许您使用它,则可以安全地使用它.否则,您需要使用另一种方法,该方法将锁定.

Rust相关问答推荐

关联类型(类型参数)命名约定

Rust中的相互递归特性与默认实现

如何使用字符串迭代器执行查找?

在Rust中宏的表达式中提取对象

如何为rust trait边界指定多种可能性

闭包不会发送,即使它只捕获发送变量

有没有可能让泛型Rust T总是堆分配的?

`*mut[T]`与`*mut T`的区别

在Rust内联程序集中使用字符串常量

当我try 使用 SKI 演算中的S I I实现递归时,为什么 Rust 会失败?

Rust中的一生语法有什么作用?

trait 对象指针的生命周期

str 和 String 的 Rust 生命周期

如何在 Rust 中将枚举变体转换为 u8?

Rust:`sort_by` 多个条件,冗长的模式匹配

如何获取函数中borrow 的切片的第一部分?

从现有系列和 map 值创建新系列

返回引用字符串的future

隐式类型闭包的错误生命周期推断

TinyVec 如何与 Vec 大小相同?