rust/src/doc/trpl/mutability.md

182 lines
4.3 KiB
Markdown
Raw Normal View History

2015-04-07 21:16:02 -05:00
% Mutability
2015-04-23 14:09:25 -05:00
Mutability, the ability to change something, works a bit differently in Rust
than in other languages. The first aspect of mutability is its non-default
status:
```rust,ignore
let x = 5;
x = 6; // error!
```
We can introduce mutability with the `mut` keyword:
```rust
let mut x = 5;
x = 6; // no problem!
```
This is a mutable [variable binding][vb]. When a binding is mutable, it means
youre allowed to change what the binding points to. So in the above example,
its not so much that the value at `x` is changing, but that the binding
changed from one `i32` to another.
[vb]: variable-bindings.html
If you want to change what the binding points to, youll need a [mutable reference][mr]:
```rust
let mut x = 5;
let y = &mut x;
```
[mr]: references-and-borrowing.html
`y` is an immutable binding to a mutable reference, which means that you cant
bind `y` to something else (`y = &mut z`), but you can mutate the thing thats
2015-05-14 11:20:33 -05:00
bound to `y` (`*y = 5`). A subtle distinction.
2015-04-23 14:09:25 -05:00
Of course, if you need both:
```rust
let mut x = 5;
let mut y = &mut x;
```
Now `y` can be bound to another value, and the value its referencing can be
changed.
Its important to note that `mut` is part of a [pattern][pattern], so you
can do things like this:
```rust
let (mut x, y) = (5, 6);
fn foo(mut x: i32) {
# }
```
[pattern]: patterns.html
# Interior vs. Exterior Mutability
However, when we say something is immutable in Rust, that doesnt mean that
2015-09-07 03:01:01 -05:00
its not able to be changed: we mean something has exterior mutability. Consider,
2015-04-23 14:09:25 -05:00
for example, [`Arc<T>`][arc]:
```rust
use std::sync::Arc;
let x = Arc::new(5);
let y = x.clone();
```
[arc]: ../std/sync/struct.Arc.html
When we call `clone()`, the `Arc<T>` needs to update the reference count. Yet
weve not used any `mut`s here, `x` is an immutable binding, and we didnt take
`&mut 5` or anything. So what gives?
2015-05-09 22:25:09 -05:00
To understand this, we have to go back to the core of Rusts guiding
philosophy, memory safety, and the mechanism by which Rust guarantees it, the
2015-04-23 14:09:25 -05:00
[ownership][ownership] system, and more specifically, [borrowing][borrowing]:
> You may have one or the other of these two kinds of borrows, but not both at
> the same time:
>
2015-09-07 03:03:53 -05:00
> * one or more references (`&T`) to a resource,
> * exactly one mutable reference (`&mut T`).
2015-04-23 14:09:25 -05:00
[ownership]: ownership.html
2015-05-30 16:43:23 -05:00
[borrowing]: references-and-borrowing.html#borrowing
2015-04-23 14:09:25 -05:00
So, thats the real definition of immutability: is this safe to have two
pointers to? In `Arc<T>`s case, yes: the mutation is entirely contained inside
the structure itself. Its not user facing. For this reason, it hands out `&T`
with `clone()`. If it handed out `&mut T`s, though, that would be a problem.
Other types, like the ones in the [`std::cell`][stdcell] module, have the
opposite: interior mutability. For example:
```rust
use std::cell::RefCell;
let x = RefCell::new(42);
let y = x.borrow_mut();
```
[stdcell]: ../std/cell/index.html
RefCell hands out `&mut` references to whats inside of it with the
`borrow_mut()` method. Isnt that dangerous? What if we do:
```rust,ignore
use std::cell::RefCell;
let x = RefCell::new(42);
let y = x.borrow_mut();
let z = x.borrow_mut();
# (y, z);
```
This will in fact panic, at runtime. This is what `RefCell` does: it enforces
Rusts borrowing rules at runtime, and `panic!`s if theyre violated. This
allows us to get around another aspect of Rusts mutability rules. Lets talk
about it first.
## Field-level mutability
Mutability is a property of either a borrow (`&mut`) or a binding (`let mut`).
2015-04-23 14:09:25 -05:00
This means that, for example, you cannot have a [`struct`][struct] with
some fields mutable and some immutable:
```rust,ignore
struct Point {
x: i32,
mut y: i32, // nope
}
```
The mutability of a struct is in its binding:
```rust,ignore
struct Point {
x: i32,
y: i32,
}
let mut a = Point { x: 5, y: 6 };
a.x = 10;
let b = Point { x: 5, y: 6};
b.x = 10; // error: cannot assign to immutable field `b.x`
```
[struct]: structs.html
2015-06-02 08:37:54 -05:00
However, by using [`Cell<T>`][cell], you can emulate field-level mutability:
2015-04-23 14:09:25 -05:00
```rust
2015-04-23 14:09:25 -05:00
use std::cell::Cell;
struct Point {
x: i32,
y: Cell<i32>,
}
let point = Point { x: 5, y: Cell::new(6) };
2015-04-23 14:09:25 -05:00
point.y.set(7);
println!("y: {:?}", point.y);
```
2015-06-02 08:37:54 -05:00
[cell]: ../std/cell/struct.Cell.html
2015-04-23 14:09:25 -05:00
This will print `y: Cell { value: 7 }`. Weve successfully updated `y`.