Skip to content

Commit

Permalink
Rollup merge of rust-lang#24466 - steveklabnik:more_more_more, r=alex…
Browse files Browse the repository at this point in the history
…crichton

Link to the big chapter for now, and add move semantics.
  • Loading branch information
Manishearth committed Apr 18, 2015
2 parents a81ce5f + e5631f9 commit 514e06d
Show file tree
Hide file tree
Showing 3 changed files with 105 additions and 3 deletions.
2 changes: 1 addition & 1 deletion src/doc/trpl/lifetimes.md
Original file line number Diff line number Diff line change
@@ -1,3 +1,3 @@
% Lifetimes

Coming soon!
Coming Soon! Until then, check out the [ownership](ownership.html) chapter.
104 changes: 103 additions & 1 deletion src/doc/trpl/move-semantics.md
Original file line number Diff line number Diff line change
@@ -1,3 +1,105 @@
% Move Semantics

Coming Soon
An important aspect of [ownership][ownership] is ‘move semantics’. Move
semantics control how and when ownership is transferred between bindings.

[ownership]: ownership.html

For example, consider a type like `Vec<T>`, which owns its contents:

```rust
let v = vec![1, 2, 3];
```

I can assign this vector to another binding:

```rust
let v = vec![1, 2, 3];

let v2 = v;
```

But, if we try to use `v` afterwards, we get an error:

```rust,ignore
let v = vec![1, 2, 3];
let v2 = v;
println!("v[0] is: {}", v[0]);
```

It looks like this:

```text
error: use of moved value: `v`
println!("v[0] is: {}", v[0]);
^
```

A similar thing happens if we define a function which takes ownership, and
try to use something after we’ve passed it as an argument:

```rust
fn take(v: Vec<i32>) {
// what happens here isn’t important.
}

let v = vec![1, 2, 3];

take(v);

println!("v[0] is: {}", v[0]);
```

Same error: “use of moved value.” When we transfer ownership to something else,
we say that we’ve ‘moved’ the thing we refer to. You don’t need some sort of
special annotation here, it’s the default thing that Rust does.

# The details

The reason that we cannot use a binding after we’ve moved it is subtle, but
important. When we write code like this:

```rust
let v = vec![1, 2, 3];

let v2 = v;
```

The first line creates some data for the vector on the stack, `v`. The vector’s
data, however, is stored on the heap, and so it contains a pointer to that
data. When we move `v` to `v2`, it creates a copy of that data, for `v2`. Which
would mean two pointers to the contents of the vector on the heap. That would
be a problem: it would violate Rust’s safety guarantees by introducing a data
race. Therefore, Rust forbids using `v` after we’ve done the move.

It’s also important to note that optimizations may remove the actual copy of
the bytes, depending on circumstances. So it may not be as inefficient as it
initially seems.

# `Copy` types

We’ve established that when ownership is transferred to another binding, you
cannot use the original binding. However, there’s a [trait][traits] that changes this
behavior, and it’s called `Copy`. We haven’t discussed traits yet, but for now,
you can think of them as an annotation to a particular type that adds extra
behavior. For example:

```rust
let v = 1;

let v2 = v;

println!("v is: {}", v);
```

In this case, `v` is an `i32`, which implements the `Copy` trait. This means
that, just like a move, when we assign `v` to `v2`, a copy of the data is made.
But, unlike a move, we can still use `v` afterward. This is because an `i32`
has no pointers to data somewhere else, copying it is a full copy.

We will discuss how to make your own types `Copy` in the [traits][traits]
section.

[traits]: traits.html
2 changes: 1 addition & 1 deletion src/doc/trpl/references-and-borrowing.md
Original file line number Diff line number Diff line change
@@ -1,3 +1,3 @@
% References and Borrowing

Coming Soon!
Coming Soon! Until then, check out the [ownership](ownership.html) chapter.

0 comments on commit 514e06d

Please # to comment.