Skip to content

Commit e5631f9

Browse files
committed
TRPL: move semantics
1 parent 54abe4c commit e5631f9

File tree

1 file changed

+103
-1
lines changed

1 file changed

+103
-1
lines changed

src/doc/trpl/move-semantics.md

Lines changed: 103 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,105 @@
11
% Move Semantics
22

3-
Coming Soon
3+
An important aspect of [ownership][ownership] is ‘move semantics’. Move
4+
semantics control how and when ownership is transferred between bindings.
5+
6+
[ownership]: ownership.html
7+
8+
For example, consider a type like `Vec<T>`, which owns its contents:
9+
10+
```rust
11+
let v = vec![1, 2, 3];
12+
```
13+
14+
I can assign this vector to another binding:
15+
16+
```rust
17+
let v = vec![1, 2, 3];
18+
19+
let v2 = v;
20+
```
21+
22+
But, if we try to use `v` afterwards, we get an error:
23+
24+
```rust,ignore
25+
let v = vec![1, 2, 3];
26+
27+
let v2 = v;
28+
29+
println!("v[0] is: {}", v[0]);
30+
```
31+
32+
It looks like this:
33+
34+
```text
35+
error: use of moved value: `v`
36+
println!("v[0] is: {}", v[0]);
37+
^
38+
```
39+
40+
A similar thing happens if we define a function which takes ownership, and
41+
try to use something after we’ve passed it as an argument:
42+
43+
```rust
44+
fn take(v: Vec<i32>) {
45+
// what happens here isn’t important.
46+
}
47+
48+
let v = vec![1, 2, 3];
49+
50+
take(v);
51+
52+
println!("v[0] is: {}", v[0]);
53+
```
54+
55+
Same error: “use of moved value.” When we transfer ownership to something else,
56+
we say that we’ve ‘moved’ the thing we refer to. You don’t need some sort of
57+
special annotation here, it’s the default thing that Rust does.
58+
59+
# The details
60+
61+
The reason that we cannot use a binding after we’ve moved it is subtle, but
62+
important. When we write code like this:
63+
64+
```rust
65+
let v = vec![1, 2, 3];
66+
67+
let v2 = v;
68+
```
69+
70+
The first line creates some data for the vector on the stack, `v`. The vector’s
71+
data, however, is stored on the heap, and so it contains a pointer to that
72+
data. When we move `v` to `v2`, it creates a copy of that data, for `v2`. Which
73+
would mean two pointers to the contents of the vector on the heap. That would
74+
be a problem: it would violate Rust’s safety guarantees by introducing a data
75+
race. Therefore, Rust forbids using `v` after we’ve done the move.
76+
77+
It’s also important to note that optimizations may remove the actual copy of
78+
the bytes, depending on circumstances. So it may not be as inefficient as it
79+
initially seems.
80+
81+
# `Copy` types
82+
83+
We’ve established that when ownership is transferred to another binding, you
84+
cannot use the original binding. However, there’s a [trait][traits] that changes this
85+
behavior, and it’s called `Copy`. We haven’t discussed traits yet, but for now,
86+
you can think of them as an annotation to a particular type that adds extra
87+
behavior. For example:
88+
89+
```rust
90+
let v = 1;
91+
92+
let v2 = v;
93+
94+
println!("v is: {}", v);
95+
```
96+
97+
In this case, `v` is an `i32`, which implements the `Copy` trait. This means
98+
that, just like a move, when we assign `v` to `v2`, a copy of the data is made.
99+
But, unlike a move, we can still use `v` afterward. This is because an `i32`
100+
has no pointers to data somewhere else, copying it is a full copy.
101+
102+
We will discuss how to make your own types `Copy` in the [traits][traits]
103+
section.
104+
105+
[traits]: traits.html

0 commit comments

Comments
 (0)