参考和框之间的可变性差异

Difference in mutability between reference and box

我正在尝试了解 Rust 指针类型及其与可变性的关系。具体来说,声明一个保存指针且本身可变的变量的方法——即可以指向其他内存,并声明 数据本身 是可变的——即可以是通过更改了指针变量的值。

我是这样理解普通引用的工作方式的:

let mut a = &5; // a is a mutable pointer to immutable data
let b = &mut 5; // b is an immutable pointer to mutable data

因此 a 可以更改为指向其他内容,而 b 不能。但是b指向的数据可以通过b改变,而不能通过a改变。 我理解正确吗?

对于问题的第二部分——为什么 Box::new 的行为似乎有所不同?这是我目前的理解:

let mut a = Box::new(5); // a is a mutable pointer to mutable data
let c = Box::new(7); // c is an immutable pointer to immutable data

new 应该 return 指向一些堆分配数据的指针,但它指向的数据似乎从保存指针的变量继承了可变性,这与带有引用的示例不同这两种可变状态是独立的! Box::new 应该如何工作? 如果是这样,我如何创建一个指针值指向存储在不可变变量中的堆上​​的可变数据?

首先,您了解引用的正确行为方式。 mut a 是一个可变变量(或者更准确地说,是一个可变绑定),而 &mut 5 是一个指向可变数据片段的可变引用(为您隐式分配在堆栈上)。

其次,Box 与引用的行为不同,因为它与引用根本不同Box 的另一个名称是 owning/owned 指针 。每个 Box 拥有 它持有的数据,并且它 唯一地 这样做,因此该数据的可变性继承自盒子的可变性本身。所以是的,这正是 Box 应该如何工作。

另一种可能更实用的理解方法是考虑 Box<T> 完全等同于 T,除了固定大小和分配方法。换句话说,Box 提供值语义:它像任何值一样移动,它的可变性取决于它存储的绑定。

有几种方法可以创建指向堆上可变数据块的指针,同时保持指针不可变。最通用的是 RefCell:

use std::cell::RefCell;

struct X { id: u32 }
let x: Box<RefCell<X>> = Box::new(RefCell::new(X { id: 0 }));
x.borrow_mut().id = 1;

或者,您可以使用 Cell(对于 Copy 类型):

let x: Box<Cell<u32>> = Box::new(Cell::new(0));
x.set(1);

请注意,以上示例使用了所谓的 "internal mutability",最好避免使用,除非您 确实 需要它。如果你想创建一个内部可变的 Box 只是为了保持可变性,你真的不应该这样做。这不是惯用语,只会导致句法和语义负担。

您可以在这里找到很多有用的信息:

事实上,如果你对诸如可变性这样的基本问题有疑问,这本书可能已经解释过了:)