参考和框之间的可变性差异
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
只是为了保持可变性,你真的不应该这样做。这不是惯用语,只会导致句法和语义负担。
您可以在这里找到很多有用的信息:
- Ownership
- References and borrowing
- Mutability
- std::cell - 内部可变性类型
事实上,如果你对诸如可变性这样的基本问题有疑问,这本书可能已经解释过了:)
我正在尝试了解 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
只是为了保持可变性,你真的不应该这样做。这不是惯用语,只会导致句法和语义负担。
您可以在这里找到很多有用的信息:
- Ownership
- References and borrowing
- Mutability
- std::cell - 内部可变性类型
事实上,如果你对诸如可变性这样的基本问题有疑问,这本书可能已经解释过了:)