]>
Commit | Line | Data |
---|---|---|
8bb4bdeb | 1 | # Mutability |
9346a6ac | 2 | |
bd371182 AL |
3 | Mutability, the ability to change something, works a bit differently in Rust |
4 | than in other languages. The first aspect of mutability is its non-default | |
5 | status: | |
6 | ||
7 | ```rust,ignore | |
8 | let x = 5; | |
476ff2be | 9 | x = 6; // Error! |
bd371182 AL |
10 | ``` |
11 | ||
12 | We can introduce mutability with the `mut` keyword: | |
13 | ||
14 | ```rust | |
15 | let mut x = 5; | |
16 | ||
476ff2be | 17 | x = 6; // No problem! |
bd371182 AL |
18 | ``` |
19 | ||
20 | This is a mutable [variable binding][vb]. When a binding is mutable, it means | |
21 | you’re allowed to change what the binding points to. So in the above example, | |
22 | it’s not so much that the value at `x` is changing, but that the binding | |
23 | changed from one `i32` to another. | |
24 | ||
25 | [vb]: variable-bindings.html | |
26 | ||
a7813a04 | 27 | You can also create a [reference][ref] to it, using `&x`, but if you want to use the reference to change it, you will need a mutable reference: |
bd371182 AL |
28 | |
29 | ```rust | |
30 | let mut x = 5; | |
31 | let y = &mut x; | |
32 | ``` | |
33 | ||
a7813a04 | 34 | [ref]: references-and-borrowing.html |
bd371182 | 35 | |
a7813a04 | 36 | `y` is an immutable binding to a mutable reference, which means that you can’t bind 'y' to something else (`y = &mut z`), but `y` can be used to bind `x` to something else (`*y = 5`). A subtle distinction. |
bd371182 AL |
37 | |
38 | Of course, if you need both: | |
39 | ||
40 | ```rust | |
41 | let mut x = 5; | |
42 | let mut y = &mut x; | |
43 | ``` | |
44 | ||
45 | Now `y` can be bound to another value, and the value it’s referencing can be | |
46 | changed. | |
47 | ||
48 | It’s important to note that `mut` is part of a [pattern][pattern], so you | |
49 | can do things like this: | |
50 | ||
51 | ```rust | |
52 | let (mut x, y) = (5, 6); | |
53 | ||
54 | fn foo(mut x: i32) { | |
55 | # } | |
56 | ``` | |
57 | ||
a7813a04 XL |
58 | Note that here, the `x` is mutable, but not the `y`. |
59 | ||
bd371182 AL |
60 | [pattern]: patterns.html |
61 | ||
62 | # Interior vs. Exterior Mutability | |
63 | ||
64 | However, when we say something is ‘immutable’ in Rust, that doesn’t mean that | |
5bcae85e SL |
65 | it’s not able to be changed: we are referring to its ‘exterior mutability’ that |
66 | in this case is immutable. Consider, for example, [`Arc<T>`][arc]: | |
bd371182 AL |
67 | |
68 | ```rust | |
69 | use std::sync::Arc; | |
70 | ||
71 | let x = Arc::new(5); | |
72 | let y = x.clone(); | |
73 | ``` | |
74 | ||
cc61c64b | 75 | [arc]: ../../std/sync/struct.Arc.html |
bd371182 AL |
76 | |
77 | When we call `clone()`, the `Arc<T>` needs to update the reference count. Yet | |
78 | we’ve not used any `mut`s here, `x` is an immutable binding, and we didn’t take | |
79 | `&mut 5` or anything. So what gives? | |
80 | ||
81 | To understand this, we have to go back to the core of Rust’s guiding | |
82 | philosophy, memory safety, and the mechanism by which Rust guarantees it, the | |
83 | [ownership][ownership] system, and more specifically, [borrowing][borrowing]: | |
84 | ||
85 | > You may have one or the other of these two kinds of borrows, but not both at | |
86 | > the same time: | |
b039eaaf | 87 | > |
e9174d1e SL |
88 | > * one or more references (`&T`) to a resource, |
89 | > * exactly one mutable reference (`&mut T`). | |
bd371182 AL |
90 | |
91 | [ownership]: ownership.html | |
62682a34 | 92 | [borrowing]: references-and-borrowing.html#borrowing |
bd371182 AL |
93 | |
94 | So, that’s the real definition of ‘immutability’: is this safe to have two | |
95 | pointers to? In `Arc<T>`’s case, yes: the mutation is entirely contained inside | |
96 | the structure itself. It’s not user facing. For this reason, it hands out `&T` | |
97 | with `clone()`. If it handed out `&mut T`s, though, that would be a problem. | |
98 | ||
99 | Other types, like the ones in the [`std::cell`][stdcell] module, have the | |
100 | opposite: interior mutability. For example: | |
101 | ||
102 | ```rust | |
103 | use std::cell::RefCell; | |
104 | ||
105 | let x = RefCell::new(42); | |
106 | ||
107 | let y = x.borrow_mut(); | |
108 | ``` | |
109 | ||
cc61c64b | 110 | [stdcell]: ../../std/cell/index.html |
bd371182 AL |
111 | |
112 | RefCell hands out `&mut` references to what’s inside of it with the | |
113 | `borrow_mut()` method. Isn’t that dangerous? What if we do: | |
114 | ||
115 | ```rust,ignore | |
116 | use std::cell::RefCell; | |
117 | ||
118 | let x = RefCell::new(42); | |
119 | ||
120 | let y = x.borrow_mut(); | |
121 | let z = x.borrow_mut(); | |
122 | # (y, z); | |
123 | ``` | |
124 | ||
125 | This will in fact panic, at runtime. This is what `RefCell` does: it enforces | |
126 | Rust’s borrowing rules at runtime, and `panic!`s if they’re violated. This | |
127 | allows us to get around another aspect of Rust’s mutability rules. Let’s talk | |
128 | about it first. | |
129 | ||
130 | ## Field-level mutability | |
131 | ||
132 | Mutability is a property of either a borrow (`&mut`) or a binding (`let mut`). | |
133 | This means that, for example, you cannot have a [`struct`][struct] with | |
134 | some fields mutable and some immutable: | |
135 | ||
136 | ```rust,ignore | |
137 | struct Point { | |
138 | x: i32, | |
476ff2be | 139 | mut y: i32, // Nope. |
bd371182 AL |
140 | } |
141 | ``` | |
142 | ||
143 | The mutability of a struct is in its binding: | |
144 | ||
145 | ```rust,ignore | |
146 | struct Point { | |
147 | x: i32, | |
148 | y: i32, | |
149 | } | |
150 | ||
151 | let mut a = Point { x: 5, y: 6 }; | |
152 | ||
153 | a.x = 10; | |
154 | ||
7cac9316 | 155 | let b = Point { x: 5, y: 6 }; |
bd371182 | 156 | |
476ff2be | 157 | b.x = 10; // Error: cannot assign to immutable field `b.x`. |
bd371182 AL |
158 | ``` |
159 | ||
160 | [struct]: structs.html | |
161 | ||
62682a34 | 162 | However, by using [`Cell<T>`][cell], you can emulate field-level mutability: |
bd371182 | 163 | |
62682a34 | 164 | ```rust |
bd371182 AL |
165 | use std::cell::Cell; |
166 | ||
167 | struct Point { | |
168 | x: i32, | |
169 | y: Cell<i32>, | |
170 | } | |
171 | ||
172 | let point = Point { x: 5, y: Cell::new(6) }; | |
173 | ||
174 | point.y.set(7); | |
175 | ||
176 | println!("y: {:?}", point.y); | |
177 | ``` | |
178 | ||
cc61c64b | 179 | [cell]: ../../std/cell/struct.Cell.html |
62682a34 | 180 | |
bd371182 | 181 | This will print `y: Cell { value: 7 }`. We’ve successfully updated `y`. |