假设我们声明了一个不可变(不是let mut)RwLock实例,如下所示:

let value = RwLock::new(0);

因为value是一成不变的,我以为我不能改变RwLock的内在价值.然而,当我测试时,显然这是有效的:

{
  *value.write().unwrap() = 5;
}

我想知道我是否以错误的方式使用了RwLock,这不应该发生(如果是这样的话,我担心锁可能不会像预期的那样工作).然而,我相信这种行为背后有一些解释,因为当谈到你可以改变什么和不可以改变什么时,拉斯特非常明确.

我的猜测是,RwLock将其内部值存储在堆中,因此它只需要跟踪指向该值的不变指针.因此,只要我们写入值,RwLock struct 本身就会保持不变,因为指针不会改变.

这只是一个猜测,很可能是一个错误的猜测.如果有人愿意纠正我,我非常高兴.


For clarification: I know how Reader-Writer locks are supposed to work. My question is not about the synchronization mechanism, but rather why doesn't Rust treat 100 values like any other value when it comes to immutability. Like is it one of the "magic" types that compiler treats differently, or there's something else I am not aware of.

推荐答案

因为就编译器而言,您并没有改变RwLock.

RwLock::write()&self作为接收者,并返回RwLockWriteGuard,其中DerefMut-impl用于执行赋值*value... = 5.在这些步骤之间发生的事情取决于RwLock的实施.

Since you are specifically asking not about RwLock per se, but the presence or non-presence of "magic": There is absolutely no magic involved here with respect to immutable (&) or mutable (&mut) references. In fact, there may be a misunderstanding:
While we call these "immutable" or "mutable" (because that's how they are used), those are better thought of as "shared" and "exclusive" references. With an exclusive reference (&mut), you are always free to mutate the value without causing mutation-while-aliasing; the compiler can guarantee this (special) use case. Likewise, with shared references (&), you are free to alias the value as mutation is not possible. The compiler can also guarantee this (special) case.
While this covers a surprisingly large number of situations, with RwLock this is neither possible nor desirable. The RwLock uses it's internal locking mechanism (that the compiler can't know about) to determine if mutation should be allowed, and upholds the guarantee that mutation-while-aliasing does not occur. That is why RwLock can go from a &self to mutating the inner value.

同样的道理也适用于RefCell型BTW.

Rust相关问答推荐

将内部类型作为参数的泛型 struct 上的方法

如何创建引用构造函数拥有的变量的对象?

常量泛型和类型枚举箱有重叠的用途吗?

我如何在Rust中使用传递依赖中的特征?

如何在Rust中表示仅具有特定大小的数组

亚性状上位性状上的 rust 病伴生型界限

Box::new()会从一个堆栈复制到另一个堆吗?

使用Clap时如何将String作为Into Str参数传递?

完全匹配包含大小写的整数范围(&Q;)

Rust移动/复制涉及实际复制时进行检测

为什么RefCell没有与常规引用相同的作用域?

tokio::sync::broadcast::Receiver 不是克隆

通过写入 std::io::stdout() 输出不可见

如何在 Rust 中显式声明 std::str::Matches<'a, P> ?

从光标位置旋转精灵

简单 TCP 服务器的连接由对等重置错误,mio 负载较小

std::vector::shrink_to_fit 如何在 Rust 中工作?

在 Rust 中,Weak 如何知道内部值何时被删除?

为什么允许重新分配 String 而不是 *&String

Rust 中函数的类型同义词