Small wording, punctuation, spelling edits

This commit is contained in:
Carol (Nichols || Goulding) 2016-07-21 16:50:21 -04:00
parent 4de58546ae
commit d9591c1928
2 changed files with 33 additions and 32 deletions

View File

@ -3,7 +3,7 @@
Rust's standard library includes a number of really useful data structures
called 'collections'. Most types represent one specific value, but collections
can contain multiple values inside of them. Each collection has different
capabilities and costs, and chosing an appropriate one for the situation you're
capabilities and costs, and choosing an appropriate one for the situation you're
in is a skill you'll develop over time. In this chapter, we'll go over three
collections which are used very often in Rust programs:
@ -13,4 +13,4 @@ collections which are used very often in Rust programs:
* *HashMap*s allow you to associate a value with a particular key.
There are more specialized variants of each of these data structures for
special situations, but these ones are the most fundamental.
special situations, but these are the most fundamental.

View File

@ -1,7 +1,7 @@
# Vectors
The first type we'll look at is `Vec<T>`, also known as a 'vector'. Vectors
allow you to store more than one value in a single data structure, next to each
allow you to store more than one value in a single data structure next to each
other in memory.
## Creating a new vector
@ -13,10 +13,10 @@ let v: Vec<i32> = Vec::new();
```
You'll note that we added a type annotation here. Because we don't actually do
anything with the vector, Rust doesn't know what sort of elements we intend to
store. This is an important point. Vectors are homogenous; they may store many
values, but those values must be all of the same type. Vectors are generic over
the type you store inside them, so we use the angle brackets to tell Rust that
anything with the vector, Rust doesn't know what kind of elements we intend to
store. This is an important point. Vectors are homogenous: they may store many
values, but those values must all be the same type. Vectors are generic over
the type you store inside them, and the angle brackets here tell Rust that
this vector will hold elements of the `i32` type.
That said, in real code, you very rarely need to do this type annotation. Let's
@ -53,14 +53,14 @@ struct Vec<T> {
}
```
This is not literally true, but will help you gain some intutions about it at
a high level. The actual representation is quite involved, and you can [read a
chapter in the Nomicon][nomicon] for the full details.
This is not literally true, but will help you gain some intutions about it. The
actual representation is quite involved, and you can [read a chapter in the
Nomicon][nomicon] for the full details.
[nomicon]: https://doc.rust-lang.org/stable/nomicon/vec.html
At a high level, though, this is okay: a vector has a reference to some data,
a capacity, and a length. Let's go through these lines of code, and see how
a capacity, and a length. Let's go through these lines of code and see how
the vector changes.
```rust
@ -123,14 +123,13 @@ v.push(6);
# v.push(8);
```
Same thing, we `push` a `6`. And, in this case, the same thing will happen:
Same thing, we `push` a `6`. In this case, the same thing will happen:
`push` looks at the values of `capacity` and `len`, and sees that we don't have
room for a second element. So here's what it does: it requests room for twice
as many elements as we currently have. In this case, that means two elements.
It then copies the existing element over into the new memory allocation, and
then copies the `6` into the next open slot. After updating the internal
values, it now looks like this:
Once it gets the memory it requested, the code in `push` copies the existing
element over into the new memory allocation then copies the `6` into the next
open slot. After updating the internal values, the vector now looks like this:
```text
struct Vec<T> {
@ -141,7 +140,7 @@ struct Vec<T> {
```
Our `capacity` and `length` both show two here. Let's try inserting another
elment into the vector:
element into the vector:
```rust
# let mut v = Vec::new();
@ -154,7 +153,7 @@ v.push(7);
Same story here: `push` looks and sees that our vector is full. However,
this time, something is slightly different. We currently have a capacity of
two elements. So the vector will request memory for double that number of
two elements, so the vector will request memory for double that number of
elements from the operating system: four. But why does it double every time?
We'll learn about that soon. For now, `push` will then copy the first two
elements over to the new memory, copy our `7` onto the end, and then update
@ -170,11 +169,12 @@ struct Vec<T> {
Ah ha! A difference. In essence, `capacity` tracks how much memory we've got
saved away for holding elements. `length` keeps track of how many elements we
are actually storing. Why not just allocate exactly how much we need? In order
to get more heap memory, we have to talk to the operating system, and that's
slower. Not only that, but we have to copy the contents of the vector from the
old memory to the new memory each time. So we make a tradeoff: we allocate a
bit more memory than we need, but in exchange, we get speed.
are actually storing. Why not just allocate exactly as much as we need? In order
to get more heap memory, we have to talk to the operating system, and that
takes time. Not only that, but each time we get chunk of memory, we have to
copy the contents of the vector from the old memory to the new memory. So we
make a tradeoff: we request a bit more memory than we need, but in exchange,
we speed up the next few `push` operations.
We can see this speed the next time we call `push`:
@ -189,7 +189,7 @@ v.push(7);
Now, `push` looks at the capacity versus the length: we have room for four
elements, but we only have three elements. Perfect! We skip that "request more
memory from the OS and copy everything" business, and just copy the `7` into
memory from the OS and copy everything" business and just copy the `7` into
the existing memory. After updating `capacity` and `len`, it looks like this:
```text
@ -248,7 +248,8 @@ to introduce references to the elements of the vector. Let's tackle that next!
Now that we know how to make vectors, knowing how to read their contents is a
good next step. There are two ways to reference a value stored in a vector.
We've added in the return types for extra clarity:
We've annotated the types of the values that are returned from these functions
for extra clarity:
```rust
let v = vec![1, 2, 3, 4, 5];
@ -258,10 +259,10 @@ let three: Option<&i32> = v.get(2);
```
First, note that we use `2` to get the third element: vectors are indexed by
number, starting at zero. Secondly, we have two different ways to do this: `&`
and `[]`s, and a method, `get`. The square brackets give us a reference, and
`get` gives us an `Option<&T>`. Why two ways? Well, what happens if we tried to
do this:
number, starting at zero. Secondly, we have two different ways to do this:
using `&` and `[]`s and using a method, `get()`. The square brackets give us a
reference, and `get()` gives us an `Option<&T>`. Why two ways? Well, what
happens if we tried to do this:
```rust,should_panic
let v = vec![1, 2, 3, 4, 5];
@ -271,11 +272,11 @@ let does_not_exist = v.get(100);
```
With the `[]`s, Rust will cause a `panic!`. With the `get` method, it will
instead return `None`. But it's important to note that while `panic!`s will
instead return `None` without `panic!`ing. Remember that while `panic!`s will
cause your program to stop executing, they do not cause memory unsafety.
The borrow checker remains vigilant about references to the contents of the
vector, and will make sure that everything stays valid. For example, here's
vector and will make sure that everything stays valid. For example, here's
a case that looks okay, but actually isn't:
```rust,ignore
@ -302,6 +303,6 @@ error: aborting due to previous error(s)
```
What's the matter here? Remember what can happen when we `push` to a vector: it
might have to go get more memory, and copy all of the values to that new
might have to go get more memory and copy all of the values to that new
memory. If it has to do this, our `first` would be pointing to old, invalid
memory!