我正在尝试理解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
应该返回指向一些堆分配数据的指针,但它指向的数据似乎从保存指针的变量继承可变性,这与带有引用的示例不同,这两个可变性状态是独立! 这是Box::new
应该如何工作的?如果是这样,我怎样才能在存储在不可变变量中的堆上创建可变数据的指针值?
答案 0 :(得分:2)
首先,您了解引用的正确行为。 mut a
是一个可变变量(或者更确切地说,是一个可变绑定),而&mut 5
是一个可变引用,指向一个可变数据片段(在你的栈中隐式分配)。 / p>
其次,Box
与引用的行为不同,因为它与引用的根本不同。 Box
的另一个名称是拥有/拥有指针。每个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);
请注意,上述示例使用的是所谓的内部可变性&#34;除非你做需要它,否则最好避免这种情况。如果你想创建一个带有可变内部的Box
只是为了保持可变性,你真的不应该这样做。它不是惯用的,只会导致句法和语义上的负担。
您可以在此处找到许多有用的信息:
事实上,如果你对可变性等基本问题有疑问,可能已在书中解释过:)