Skip to content

Commit

Permalink
auto merge of #17962 : jkleint/rust/guide-vectors, r=steveklabnik
Browse files Browse the repository at this point in the history
The array is the fundamental concept; vectors are growable arrays, and
slices are views into either.  Show common array ops up front: length
and iteration.  Mention arrays are immutable by default.  Highlight
definite initialization and bounds-checking as safety features.  Show
that you only need a type suffix on one element of initializers.
Explain that vectors are a value-add library type over arrays, not a
fundamental type; show they have the same "interface." Motivate slices
as efficient views into arrays; explain you can slice vectors, Strings,
&str because they're backed by arrays.  Show off new, easy-to-read
[a..b] slice syntax.
  • Loading branch information
bors committed Oct 15, 2014
2 parents 71dfa5b + 1ce5a56 commit e4761c8
Showing 1 changed file with 65 additions and 50 deletions.
115 changes: 65 additions & 50 deletions src/doc/guide.md
Original file line number Diff line number Diff line change
Expand Up @@ -1496,87 +1496,102 @@ low-level details matter, they really matter. Just remember that `String`s
allocate memory and control their data, while `&str`s are a reference to
another string, and you'll be all set.

# Vectors
# Arrays, Vectors, and Slices

Like many programming languages, Rust has a list type for when you want a list
of things. But similar to strings, Rust has different types to represent this
idea: `Vec<T>` (a 'vector'), `[T, .. N]` (an 'array'), and `&[T]` (a 'slice').
Whew!
Like many programming languages, Rust has list types to represent a sequence of
things. The most basic is the **array**, a fixed-size list of elements of the
same type. By default, arrays are immutable.

Vectors are similar to `String`s: they have a dynamic length, and they
allocate enough memory to fit. You can create a vector with the `vec!` macro:
```{rust}
let a = [1i, 2i, 3i];
let mut m = [1i, 2i, 3i];
```

You can create an array with a given number of elements, all initialized to the
same value, with `[val, ..N]` syntax. The compiler ensures that arrays are
always initialized.

```{rust}
let nums = vec![1i, 2i, 3i];
let a = [0i, ..20]; // Shorthand for array of 20 elements all initialized to 0
```

Notice that unlike the `println!` macro we've used in the past, we use square
brackets (`[]`) with `vec!`. Rust allows you to use either in either situation,
this is just convention.
Arrays have type `[T,..N]`. We'll talk about this `T` notation later, when we
cover generics.

You can create an array with just square brackets:
You can get the number of elements in an array `a` with `a.len()`, and use
`a.iter()` to iterate over them with a for loop. This code will print each
number in order:

```{rust}
let nums = [1i, 2i, 3i];
let nums = [1i, ..20]; // Shorthand for an array of 20 elements all initialized to 1
let a = [1i, 2, 3]; // Only the first item needs a type suffix
println!("a has {} elements", a.len());
for e in a.iter() {
println!("{}", e);
}
```

So what's the difference? An array has a fixed size, so you can't add or
subtract elements:
You can access a particular element of an array with **subscript notation**:

```{rust,ignore}
let mut nums = vec![1i, 2i, 3i];
nums.push(4i); // works
```{rust}
let names = ["Graydon", "Brian", "Niko"];
let mut nums = [1i, 2i, 3i];
nums.push(4i); // error: type `[int, .. 3]` does not implement any method
// in scope named `push`
println!("The second name is: {}", names[1]);
```

The `push()` method lets you append a value to the end of the vector. But
since arrays have fixed sizes, adding an element doesn't make any sense.
You can see how it has the exact type in the error message: `[int, .. 3]`.
An array of `int`s, with length 3.
Subscripts start at zero, like in most programming languages, so the first name
is `names[0]` and the second name is `names[1]`. The above example prints
`The second name is: Brian`. If you try to use a subscript that is not in the
array, you will get an error: array access is bounds-checked at run-time. Such
errant access is the source of many bugs in other systems programming
languages.

Similar to `&str`, a slice is a reference to another array. We can get a
slice from a vector by using the `as_slice()` method:
A **vector** is a dynamic or "growable" array, implemented as the standard
library type [`Vec<T>`](std/vec/) (we'll talk about what the `<T>` means
later). Vectors are to arrays what `String` is to `&str`. You can create them
with the `vec!` macro:

```{rust}
let vec = vec![1i, 2i, 3i];
let slice = vec.as_slice();
let v = vec![1i, 2, 3];
```

All three types implement an `iter()` method, which returns an iterator. We'll
talk more about the details of iterators later, but for now, the `iter()` method
allows you to write a `for` loop that prints out the contents of a vector, array,
or slice:
(Notice that unlike the `println!` macro we've used in the past, we use square
brackets `[]` with `vec!`. Rust allows you to use either in either situation,
this is just convention.)

```{rust}
let vec = vec![1i, 2i, 3i];
You can get the length of, iterate over, and subscript vectors just like
arrays. In addition, (mutable) vectors can grow automatically:

for i in vec.iter() {
println!("{}", i);
}
```{rust}
let mut nums = vec![1i, 2, 3];
nums.push(4);
println!("The length of nums is now {}", nums.len()); // Prints 4
```

This code will print each number in order, on its own line.
Vectors have many more useful methods.

You can access a particular element of a vector, array, or slice by using
**subscript notation**:
A **slice** is a reference to (or "view" into) an array. They are useful for
allowing safe, efficient access to a portion of an array without copying. For
example, you might want to reference just one line of a file read into memory.
By nature, a slice is not created directly, but from an existing variable.
Slices have a length, can be mutable or not, and in many ways behave like
arrays:

```{rust}
let names = ["Graydon", "Brian", "Niko"];
let a = [0i, 1, 2, 3, 4];
let middle = a.slice(1, 4); // A slice of a: just the elements [1,2,3]
println!("The second name is: {}", names[1]);
for e in middle.iter() {
println!("{}", e); // Prints 1, 2, 3
}
```

These subscripts start at zero, like in most programming languages, so the
first name is `names[0]` and the second name is `names[1]`. The above example
prints `The second name is: Brian`.
You can also take a slice of a vector, `String`, or `&str`, because they are
backed by arrays. Slices have type `&[T]`, which we'll talk about when we cover
generics.

There's a whole lot more to vectors, but that's enough to get started. We have
now learned all of the most basic Rust concepts. We're ready to start building
our guessing game, but we need to know how to do one last thing first: get
We have now learned all of the most basic Rust concepts. We're ready to start
building our guessing game, we just need to know one last thing: how to get
input from the keyboard. You can't have a guessing game without the ability to
guess!

Expand Down

0 comments on commit e4761c8

Please sign in to comment.