undo the 'sentence per line' experiment

I tried it, I didn't like it.
This commit is contained in:
Steve Klabnik 2015-12-28 10:51:03 -05:00
parent 795403668e
commit 7afd6feada
4 changed files with 333 additions and 308 deletions

View File

@ -1,8 +1,8 @@
# Comments # Comments
We strive to make our programs easy to understand, but sometimes, some extra explanation is warranted. We strive to make our programs easy to understand, but sometimes, some extra
We can leave notes in our source code that the compiler will ignore. explanation is warranted. We can leave notes in our source code that the
These notes are called comments. compiler will ignore. These notes are called comments.
Heres a comment: Heres a comment:
@ -10,8 +10,8 @@ Heres a comment:
// Hello, world. // Hello, world.
``` ```
Comments start with two slashes, and last until the end of the line. Comments start with two slashes, and last until the end of the line. Larger
Larger comments will need more lines: comments will need more lines:
```rust ```rust
// So were doing something complicated here, long enough that we need // So were doing something complicated here, long enough that we need
@ -40,9 +40,10 @@ Thats all there is to it. Comments are not particularly complicated.
## Documentation comments ## Documentation comments
However, Rust has another kind of comment: a documentation comment. However, Rust has another kind of comment: a documentation comment. These
These comments dont affect the way that the code works, but they do work with Rusts tools. comments dont affect the way that the code works, but they do work with Rusts
More specifically, the `rustdoc` tool that comes with Rust reads documentation comments and produces HTML documentation from them. tools. More specifically, the `rustdoc` tool that comes with Rust reads
documentation comments and produces HTML documentation from them.
Documentation comments use an extra slash: Documentation comments use an extra slash:
@ -58,11 +59,12 @@ fn bar() {
} }
``` ```
This comment would then be interpreted by `rustdoc` as documenting the thing that follows it: `foo()` and `bar()`. This comment would then be interpreted by `rustdoc` as documenting the thing
that follows it: `foo()` and `bar()`.
Because documentation comments have semantic meaning to `rustdoc`, the compiler will pay attention to the placement Because documentation comments have semantic meaning to `rustdoc`, the compiler
of your documentation comments. will pay attention to the placement of your documentation comments. For
For example, a program with only this: example, a program with only this:
```rust,ignore ```rust,ignore
/// What am I documenting? /// What am I documenting?
@ -78,6 +80,7 @@ src/main.rs:1 /// What am I documenting?
### Inner documentation comments ### Inner documentation comments
There is a secondary form of a documentation comment, an inner documentation comment. There is a secondary form of a documentation comment, an inner documentation
Inner documentation comments look like this: `//!`. comment. Inner documentation comments look like this: `//!`. They are only
They are only really used to document modules, however, and so we will talk about them in the modules section. really used to document modules, however, and so we will talk about them in the
modules section.

View File

@ -1,6 +1,7 @@
# Functions # Functions
Functions are pervasive in Rust code. Weve already seen the most important function, `main()`, in previous sections of the book: Functions are pervasive in Rust code. Weve already seen the most important
function, `main()`, in previous sections of the book:
```rust ```rust
fn main() { fn main() {
@ -16,9 +17,9 @@ fn another_function() {
} }
``` ```
Rust code uses `snake_case` as a style for function names: all lower case, with underscores separating words. Rust code uses `snake_case` as a style for function names: all lower case, with
(It also uses them for variable names, too.) underscores separating words. (It also uses them for variable names, too.) We
We can can call any function weve defined by using its name and some parentheses: can can call any function weve defined by using its name and some parentheses:
```rust ```rust
fn main() { fn main() {
@ -32,9 +33,9 @@ fn another_function() {
} }
``` ```
Lets start a new project to explore functions. Lets start a new project to explore functions. Open a terminal, and navigate
Open a terminal, and navigate to the directory where youd like to keep your projects. to the directory where youd like to keep your projects. From there, use Cargo
From there, use Cargo to generate a new project: to generate a new project:
```bash ```bash
$ cargo new --bin functions $ cargo new --bin functions
@ -51,8 +52,9 @@ Hello, world!
Another function. Another function.
``` ```
As we can see, the lines execute in order: first, we print out our “Hello, world!” message, and then `another_function()` is called. As we can see, the lines execute in order: first, we print out our “Hello,
It then prints its message as well. world!” message, and then `another_function()` is called. It then prints its
message as well.
## Function Arguments ## Function Arguments
@ -89,16 +91,17 @@ Declaring a function which takes a single argument looks like this:
fn NAME(PATTERN: TYPE) { fn NAME(PATTERN: TYPE) {
``` ```
Thats right, patterns appear again. Thats right, patterns appear again. Consider how the parameter declaration
Consider how the parameter declaration here looks like the `let` bindings we used earlier: here looks like the `let` bindings we used earlier:
```rust,ignore ```rust,ignore
let x: i32; let x: i32;
fn another_function(x: i32) { fn another_function(x: i32) {
``` ```
Theres only one difference here: in function signatures, we _must_ declare the type. Theres only one difference here: in function signatures, we _must_ declare the
This is a deliberate decision; we find that requiring type annotations in functions means that you almost never need them anywhere else. type. This is a deliberate decision; we find that requiring type annotations in
functions means that you almost never need them anywhere else.
You can separate multiple arguments with a comma: You can separate multiple arguments with a comma:
@ -155,9 +158,10 @@ The value of x is: 5
The value of y is: 6 The value of y is: 6
``` ```
Note that our bindings are called `a` and `b`, yet inside of the function, we refer to them by the names in the signature, `x` and `y`. Note that our bindings are called `a` and `b`, yet inside of the function, we
Inside a function, only its parameters are in scope, so we need to use those names. refer to them by the names in the signature, `x` and `y`. Inside a function,
Bindings passed as parameters dont need to have the same name as the arguments. only its parameters are in scope, so we need to use those names. Bindings
passed as parameters dont need to have the same name as the arguments.
## Return values ## Return values
@ -167,8 +171,8 @@ Functions can also return values back to the function that called them:
fn NAME(PATTERN, PATTERN, PATTERN, PATTERN...) -> TYPE { fn NAME(PATTERN, PATTERN, PATTERN, PATTERN...) -> TYPE {
``` ```
We dont name return values, but we do declare their type, after an arrow: `->`. We dont name return values, but we do declare their type, after an arrow:
Heres a sample program: `->`. Heres a sample program:
```rust ```rust
fn main() { fn main() {
@ -191,9 +195,8 @@ $ cargo run
The value of x is: 5 The value of x is: 5
``` ```
Lets examine this in more detail. Lets examine this in more detail. There are two important bits. First, we can
There are two important bits. use the return value of a function to initialize a binding:
First, we can use the return value of a function to initialize a binding:
```rust,ignore ```rust,ignore
let x = five(); let x = five();
@ -213,11 +216,10 @@ fn five() -> i32 {
} }
``` ```
We have no arguments, and our return type, `i32`. We have no arguments, and our return type, `i32`. However, the body of this
However, the body of this function is a lonely `5`. function is a lonely `5`. Theres a detail here that you may or may not have
Theres a detail here that you may or may not have noticed: weve ended almost every line in our programs with a semicolon. noticed: weve ended almost every line in our programs with a semicolon.
Theres no semicolon here, though. Theres no semicolon here, though. Why not?
Why not?
The answer to this question is: The answer to this question is:
@ -228,16 +230,15 @@ Lets go over that now.
## Statements and Expressions ## Statements and Expressions
Expressions are bits of code that evaluate to a value. Expressions are bits of code that evaluate to a value. Consider some math
Consider some math operations, like this: operations, like this:
```rust,ignore ```rust,ignore
5 + 6 5 + 6
``` ```
We can evaluate this expression, and come up with a value: `11`. We can evaluate this expression, and come up with a value: `11`. In Rust, most
In Rust, most bits of code are expressions. bits of code are expressions. For example, calling a function is an expression:
For example, calling a function is an expression:
```rust,ignore ```rust,ignore
foo(5) foo(5)
@ -245,15 +246,13 @@ foo(5)
The value is equal to whatever the return value of `foo()` is. The value is equal to whatever the return value of `foo()` is.
So why does this matter? So why does this matter? Well, not everything is an expression. Some things are
Well, not everything is an expression. statements. Expressions _compute_ something, but statements _bind_ or _do_
Some things are statements. something. Its a subtle difference. Weve already seen two kinds of
Expressions _compute_ something, but statements _bind_ or _do_ something. statements: `let` statements, and `fn` declarations.
Its a subtle difference.
Weve already seen two kinds of statements: `let` statements, and `fn` declarations.
Because `let` is a statement, not an expression, you cant assign it to another binding. Because `let` is a statement, not an expression, you cant assign it to another
Heres an example that doesnt work: binding. Heres an example that doesnt work:
```rust,ignore ```rust,ignore
fn main() { fn main() {
@ -277,10 +276,9 @@ Could not compile `functions`.
We also cannot somehow assign a `fn` declaration to a binding, either. We also cannot somehow assign a `fn` declaration to a binding, either.
So whats this have to do with return values? So whats this have to do with return values? Well, `{}`, a block that we
Well, `{}`, a block that we used earlier to create new scopes, _is_ an expression. used earlier to create new scopes, _is_ an expression. Lets take a closer look
Lets take a closer look at `{}`. at `{}`. It looks like this:
It looks like this:
```text ```text
{ {
@ -289,9 +287,10 @@ It looks like this:
} }
``` ```
The `*` there means zero or more, so we can have any number of statements followed by an expression. The `*` there means zero or more, so we can have any number of statements
Since blocks are expressions themselves, we can nest blocks inside of blocks. followed by an expression. Since blocks are expressions themselves, we can nest
And since they return a value, we can use them in `let` statements: blocks inside of blocks. And since they return a value, we can use them in
`let` statements:
```rust ```rust
fn main() { fn main() {
@ -323,8 +322,9 @@ let y = {
}; };
``` ```
Since the block can contain statements, we create a new variable binding, `z`, and give it a value. Since the block can contain statements, we create a new variable binding, `z`,
We then do some math for the final expression of the block: and give it a value. We then do some math for the final expression of the
block:
```rust,ignore ```rust,ignore
{ {
@ -334,8 +334,8 @@ We then do some math for the final expression of the block:
} }
``` ```
`5 + 1 + 5` is `11`, and so the value of the entire block is `11`. `5 + 1 + 5` is `11`, and so the value of the entire block is `11`. This gets
This gets substituted into our `let` statement for `y`: substituted into our `let` statement for `y`:
```rust,ignore ```rust,ignore
let y = 11; let y = 11;
@ -343,8 +343,7 @@ let y = 11;
Hence our output saying `y` is `11`. Hence our output saying `y` is `11`.
Where else do we use blocks? As the body of functions! Where else do we use blocks? As the body of functions! Theyre very similar:
Theyre very similar:
```rust ```rust
fn main() { fn main() {
@ -376,8 +375,8 @@ The value of y is: 6
The value of y is: 6 The value of y is: 6
``` ```
In both cases, we use a block to produce a value. In both cases, we use a block to produce a value. In the first case, its
In the first case, its assigning with `let`: assigning with `let`:
```rust,ignore ```rust,ignore
let y = { let y = {
@ -391,8 +390,9 @@ fn plus_one(x: i32) -> i32 {
### Expression statements ### Expression statements
Theres one more detail about expressions and statements: a semicolon takes any expression, and turns it into a statement. Theres one more detail about expressions and statements: a semicolon takes any
Lets accidentally cause an error with `plus_one()`: expression, and turns it into a statement. Lets accidentally cause an error
with `plus_one()`:
```rust,ignore ```rust,ignore
fn main() { fn main() {
@ -406,7 +406,8 @@ fn plus_one(x: i32) -> i32 {
} }
``` ```
Instead of an expression, `x + 1`, weve now turned it into a statement, `x + 1;`. Instead of an expression, `x + 1`, weve now turned it into a statement,
`x + 1;`.
Running this gives an error: Running this gives an error:
@ -425,8 +426,9 @@ error: aborting due to previous error
Could not compile `functions`. Could not compile `functions`.
``` ```
Rust has our back here: it even suggests removing the semicolon, which fixes the error. Rust has our back here: it even suggests removing the semicolon, which fixes
But the main error message is the core of the issue: statements dont evaluate to a value, yet we want to return an `i32`. the error. But the main error message is the core of the issue: statements
dont evaluate to a value, yet we want to return an `i32`.
In practice, Rust programmers dont often think about these rules at this In practice, Rust programmers dont often think about these rules at this
level. Usually, you have a semicolon at the end of most lines, and maybe not at level. Usually, you have a semicolon at the end of most lines, and maybe not at
@ -434,8 +436,8 @@ the end of blocks.
## Multiple return values ## Multiple return values
Functions cannot directly return multiple values. Functions cannot directly return multiple values. Theres a trick, however.
Theres a trick, however. Remember the `()`s we used when showing off complex bindings? Remember the `()`s we used when showing off complex bindings?
```rust ```rust
fn main() { fn main() {
@ -443,9 +445,9 @@ fn main() {
} }
``` ```
They form something called a tuple, one of Rusts basic types. They form something called a tuple, one of Rusts basic types. A tuple is an
A tuple is an anonymous collection of elements. anonymous collection of elements. But since a tuple is a singular thing, we can
But since a tuple is a singular thing, we can use it as a way to return multiple values from functions: use it as a way to return multiple values from functions:
```rust ```rust
fn main() { fn main() {
@ -470,7 +472,8 @@ The value of x is: 5
The value of y is: 6 The value of y is: 6
``` ```
There are two interesting changes here: assigning the return value of `two_numbers()` to `x` and `y`, and the declaration of `two_numbers()` itself. There are two interesting changes here: assigning the return value of
`two_numbers()` to `x` and `y`, and the declaration of `two_numbers()` itself.
Lets look at the declaration first: Lets look at the declaration first:
@ -480,15 +483,14 @@ fn two_numbers() -> (i32, i32) {
} }
``` ```
The `(i32, i32)` should look familiar. The `(i32, i32)` should look familiar. We saw it in `let` bindings earlier:
We saw it in `let` bindings earlier:
```rust ```rust
let (x, y): (i32, i32) = (5, 6); let (x, y): (i32, i32) = (5, 6);
``` ```
The `(i32, i32)` syntax says “a tuple with two `i32`s in it.” The `(i32, i32)` syntax says “a tuple with two `i32`s in it.” The `(5, 6)`
The `(5, 6)` syntax creates a new one, with `5` and `6`. syntax creates a new one, with `5` and `6`.
This tuple is then returned, and assigned to `x` and `y`: This tuple is then returned, and assigned to `x` and `y`:
@ -498,4 +500,5 @@ let (x, y) = two_numbers();
See how all these bits fit together? See how all these bits fit together?
We call this behavior of `let` destructuring, because it takes the structure of the expression that comes after the `=` and takes it apart. We call this behavior of `let` destructuring, because it takes the structure
of the expression that comes after the `=` and takes it apart.

View File

@ -1,11 +1,12 @@
# Primitive Types # Primitive Types
Weve seen that every value in Rust has a type of some kind. Weve seen that every value in Rust has a type of some kind. There are a number
There are a number of types which are built into the language itself. of types which are built into the language itself. We call these types
We call these types primitive types, since you cant re-create them yourself. primitive types, since you cant re-create them yourself. There are, of
There are, of course, many non-primitive types provided by the standard library as well. course, many non-primitive types provided by the standard library as well.
Remember, you can rely on type inference to figure out the type of a binding, or you can annotate it explicitly: Remember, you can rely on type inference to figure out the type of a binding,
or you can annotate it explicitly:
```rust ```rust
fn main() { fn main() {
@ -15,8 +16,8 @@ fn main() {
## Integers ## Integers
Youve already seen one primitive type: `i32`. Youve already seen one primitive type: `i32`. There are a number of built-in
There are a number of built-in number types in Rust. number types in Rust.
Heres a chart of Rusts integer types: Heres a chart of Rusts integer types:
@ -28,24 +29,24 @@ Heres a chart of Rusts integer types:
| 64-bit | i64 | u64 | | 64-bit | i64 | u64 |
| arch | isize | usize | | arch | isize | usize |
We have both signed and unsigned variants of numbers, and each variant has an explicit size. We have both signed and unsigned variants of numbers, and each variant has an
Unsigned numbers are always positive, and signed numbers can be positive or negative. explicit size. Unsigned numbers are always positive, and signed numbers can be
(Think plus sign or minus sign: thats a signed number.) positive or negative. (Think plus sign or minus sign: thats a signed
Signed numbers are stored using twos compliment representation. number.) Signed numbers are stored using twos compliment representation.
Finally, `isize` and `usize` are different sizes based on the kind of computer your program is running on. Finally, `isize` and `usize` are different sizes based on the kind of computer
If you are on a 64-bit architecture, they are 64 bits, and if youre on a 32-bit one, theyre 32 bits. your program is running on. If you are on a 64-bit architecture, they are 64
bits, and if youre on a 32-bit one, theyre 32 bits.
So how do you choose from all these options? Well, if you really dont know, the defaults are a good choice: So how do you choose from all these options? Well, if you really dont know,
integer types default to `i32`. the defaults are a good choice: integer types default to `i32`. The primary use
The primary use case for `isize`/`usize` is when indexing some sort of collection. case for `isize`/`usize` is when indexing some sort of collection. Well talk
Well talk more about our first collection, arrays, in just a moment. more about our first collection, arrays, in just a moment.
## Floating-point numbers ## Floating-point numbers
Rust also has two primitive floating-point numbers: `f32` and `f64`. Rust also has two primitive floating-point numbers: `f32` and `f64`. They are
They are 32 bits and 64 bits in size, respectively. 32 bits and 64 bits in size, respectively. The default is `f64`.
The default is `f64`.
```rust ```rust
fn main() { fn main() {
@ -60,9 +61,8 @@ Floating-point numbers are represented according to the IEEE-754 standard.
## Tuples ## Tuples
The other type weve seen previously is the tuple type. The other type weve seen previously is the tuple type. Tuples have an arity,
Tuples have an arity, or size. or size. We might say “thats a 3-tuple” or “thats a 5-tuple.”
We might say “thats a 3-tuple” or “thats a 5-tuple.”
Each position in a tuple has a distinct type: Each position in a tuple has a distinct type:
@ -72,12 +72,13 @@ fn main() {
} }
``` ```
Tuples are used sparingly in Rust code. Tuples are used sparingly in Rust code. This is because the elements of a tuple
This is because the elements of a tuple are anonymous, which can make code hard to read. are anonymous, which can make code hard to read.
### Tuple indexing ### Tuple indexing
To access an element of a tuple, we use a `.` followed by the index we want to access: To access an element of a tuple, we use a `.` followed by the index we want to
access:
```rust ```rust
fn main() { fn main() {
@ -93,8 +94,8 @@ As you can see, the first index is `0`.
### Single-element tuples ### Single-element tuples
Theres one last trick with tuples: `(5)` is actually ambiguous: is it a tuple, or is it a `5` in parethesis? Theres one last trick with tuples: `(5)` is actually ambiguous: is it a tuple,
If you need to disambiguate, use a comma: or is it a `5` in parethesis? If you need to disambiguate, use a comma:
```rust ```rust
fn main() { fn main() {
@ -106,10 +107,9 @@ fn main() {
## Functions ## Functions
Theres one more type that weve been using, but you havent seen written explicitly. Theres one more type that weve been using, but you havent seen written
Functions! explicitly. Functions! Functions also have a type, and yes, you can even have
Functions also have a type, and yes, you can even have variables which hold functions! variables which hold functions! Heres an example:
Heres an example:
```rust ```rust
fn plus_one(x: i32) -> i32 { fn plus_one(x: i32) -> i32 {
@ -124,8 +124,8 @@ fn main() {
} }
``` ```
As you can see, the type is very similar to the declaration. As you can see, the type is very similar to the declaration. Here, lets put
Here, lets put them side by side: them side by side:
```rust,ignore ```rust,ignore
fn(i32) -> i32 // type fn(i32) -> i32 // type
@ -148,7 +148,8 @@ fn(i32) -> i32 {
Its the same! Well, we need to drop that `{` as well. Its the same! Well, we need to drop that `{` as well.
Finally, if youll notice in that example, we can create a binding with a function in it: Finally, if youll notice in that example, we can create a binding with a
function in it:
```rust,ignore ```rust,ignore
fn main() { fn main() {
@ -162,9 +163,8 @@ fn main() {
### Functions as arguments ### Functions as arguments
So why not just use the original name? So why not just use the original name? Well, we can pass functions as arguments
Well, we can pass functions as arguments to other functions! to other functions! Check this out:
Check this out:
```rust ```rust
fn plus_one(x: i32) -> i32 { fn plus_one(x: i32) -> i32 {
@ -208,10 +208,12 @@ Lets investigate in more detail.
fn twice(x: i32, f: fn(i32) -> i32) -> i32 { fn twice(x: i32, f: fn(i32) -> i32) -> i32 {
``` ```
This says “`twice()` is a function which takes two arguments. This says “`twice()` is a function which takes two arguments. `x` is a
`x` is a thirty-two bit integer, and `f` is a function which takes an `i32` and returns an `i32`.” thirty-two bit integer, and `f` is a function which takes an `i32` and returns
an `i32`.”
Inside of `twice()`, as you might imagine, we call the function `f` twice on `x`, and return the result. Inside of `twice()`, as you might imagine, we call the function `f` twice on
`x`, and return the result.
```rust,ignore ```rust,ignore
@ -219,17 +221,17 @@ let y = twice(x, plus_one);
let z = twice(x, plus_two); let z = twice(x, plus_two);
``` ```
The first time we call `twice()`, we pass `plus_one()` as an argument. The first time we call `twice()`, we pass `plus_one()` as an argument. And `x`
And `x` is `5`. is `5`. So `5 + 1 + 1 == 7`, hence our first line of output. The second time,
So `5 + 1 + 1 == 7`, hence our first line of output. we pass `plus_two()` instead. `5 + 2 + 2` is `9`, and our second line checks
The second time, we pass `plus_two()` instead. out too.
`5 + 2 + 2` is `9`, and our second line checks out too.
Passing functions to functions is very, very powerful. Passing functions to functions is very, very powerful.
## Booleans ## Booleans
Somewhat fundamental to all computing, Rust has a boolean type, `bool`, with two possible values: Somewhat fundamental to all computing, Rust has a boolean type, `bool`, with
two possible values:
```rust ```rust
fn main() { fn main() {
@ -242,10 +244,10 @@ Thats really all there is to say about that!
## Arrays ## Arrays
So far, weve only represented single values in a binding. So far, weve only represented single values in a binding. Sometimes, though,
Sometimes, though, its useful to have more than one value. its useful to have more than one value. These kinds of data structures are
These kinds of data structures are called collections, and arrays are the ones well learn about first. called collections, and arrays are the ones well learn about first. Arrays
Arrays look like this: look like this:
```rust ```rust
fn main() { fn main() {
@ -253,7 +255,8 @@ fn main() {
} }
``` ```
An arrays type consists of the type of the elements it contains, as well as the length: An arrays type consists of the type of the elements it contains, as well as
the length:
```rust ```rust
fn main() { fn main() {
@ -274,9 +277,10 @@ fn main() {
} }
``` ```
In this example, `first` will hold the value `1`, and `second` will be bound to `2`. In this example, `first` will hold the value `1`, and `second` will be bound to
Note that these values are copied out of the array; if the array changes, these bindings will not. `2`. Note that these values are copied out of the array; if the array changes,
Heres an example, which also shows us how we can modify elements of the array: these bindings will not. Heres an example, which also shows us how we can
modify elements of the array:
```rust ```rust
fn main() { fn main() {
@ -290,18 +294,21 @@ fn main() {
} }
``` ```
Running this example will show that `first` is still `1`. Running this example will show that `first` is still `1`. If we didnt want a
If we didnt want a copy, but instead wanted to refer to the first element, whatever its value was, we need a new concept. copy, but instead wanted to refer to the first element, whatever its value was,
Well talk about references in Section 4. we need a new concept. Well talk about references in Section 4.
One last thing: now that we are modifying the array, `a` needs to be declared `mut`. One last thing: now that we are modifying the array, `a` needs to be declared
`mut`.
Arrays are our first real data structure, and so theres a few other concepts that we havent covered in full yet. Arrays are our first real data structure, and so theres a few other concepts
There are two: the `panic!` macro, and a new way of printing things: `Debug`. that we havent covered in full yet. There are two: the `panic!` macro, and a
new way of printing things: `Debug`.
### Panic ### Panic
We showed what happens when you access elements of an array, but what if we give an invalid index? We showed what happens when you access elements of an array, but what if we
give an invalid index?
```rust,should_panic ```rust,should_panic
fn main() { fn main() {
@ -313,9 +320,9 @@ fn main() {
} }
``` ```
If we run this example, we will get an error. If we run this example, we will get an error. Lets re-use our `functions`
Lets re-use our `functions` project from before. project from before. Change your `src/main.rs` to look like the example, and
Change your `src/main.rs` to look like the example, and run it: run it:
```bash ```bash
$ cargo run $ cargo run
@ -325,8 +332,9 @@ thread <main> panicked at index out of bounds: the len is 5 but the ind
Process didnt exit successfully: `target/debug/functions` (exit code: 101) Process didnt exit successfully: `target/debug/functions` (exit code: 101)
``` ```
It says that our thread panicked, and that our program didnt exit successfully. It says that our thread panicked, and that our program didnt exit
Theres also a reason: we had a length of five, but an index of 10. successfully. Theres also a reason: we had a length of five, but an index of
10.
A panic can also be induced manually, with the `panic!` macro: A panic can also be induced manually, with the `panic!` macro:
@ -336,27 +344,24 @@ fn main() {
} }
``` ```
When the `panic!` macro runs, it will cause a panic. When the `panic!` macro runs, it will cause a panic. When a Rust program
When a Rust program panics, it starts a kind of controlled crash. panics, it starts a kind of controlled crash. The current thread of execution
The current thread of execution will stop entirely. will stop entirely. As such, panics are reserved for serious, program-ending
As such, panics are reserved for serious, program-ending errors. errors. Theyre not a general error-handling mechanism.
Theyre not a general error-handling mechanism.
So why did this code panic? So why did this code panic? Well, arrays know how many elements they hold. When
Well, arrays know how many elements they hold. we access an element via indexing, Rust will check that the index is less than
When we access an element via indexing, Rust will check that the index is less than the length. the length. If its greater, it will panic, as something is very wrong. This is
If its greater, it will panic, as something is very wrong. our first example of Rusts safety principles in action. In many low-level
This is our first example of Rusts safety principles in action. languages, this kind of check is not done. If you have an incorrect index,
In many low-level languages, this kind of check is not done. invalid memory can be accessed. Rust protects us against this kind of error.
If you have an incorrect index, invalid memory can be accessed.
Rust protects us against this kind of error.
**Steves note: this next bit might be our first advanced section, on get()?** **Steves note: this next bit might be our first advanced section, on get()?**
### Debug ### Debug
So far, weve been printing values using `{}`. So far, weve been printing values using `{}`. If we try that with an array,
If we try that with an array, though... though...
```ignore ```ignore
fn main() { fn main() {
@ -383,18 +388,18 @@ src/main.rs:4:25: 4:26 note: required by `core::fmt::Display::fmt`
error: aborting due to previous error error: aborting due to previous error
``` ```
Whew! The core of the error is this part: the trait `core::fmt::Display` is not implemented. Whew! The core of the error is this part: the trait `core::fmt::Display` is not
We havent discussed traits yet, so this is bound to be confusing! implemented. We havent discussed traits yet, so this is bound to be confusing!
Heres all we need to know for now: `println!` can do many kinds of formatting. Heres all we need to know for now: `println!` can do many kinds of formatting.
By default, `{}` implements a kind of formatting known as `Display`: output for end-users. By default, `{}` implements a kind of formatting known as `Display`: output for
The primitive types weve seen so far implement `Display`, as theres only one way youd show a `1` to a user. end-users. The primitive types weve seen so far implement `Display`, as
But with arrays, the output is less clear. theres only one way youd show a `1` to a user. But with arrays, the output is
Do you want commas or not? less clear. Do you want commas or not? What about the `[]`s?
What about the `[]`s?
Due to these questions, more complex types in the standard library do not implement `Display` formatting. Due to these questions, more complex types in the standard library do not
There is another kind of formatting, `Debug`, which is a bit different: output for programmers and debuggers. implement `Display` formatting. There is another kind of formatting, `Debug`,
We can ask `println!` to use `Debug` formatting with `:?`: which is a bit different: output for programmers and debuggers. We can ask
`println!` to use `Debug` formatting with `:?`:
```rust ```rust
fn main() { fn main() {
@ -413,13 +418,13 @@ $ cargo run
a is [1, 2, 3, 4, 5] a is [1, 2, 3, 4, 5]
``` ```
Youll see this repeated later, with other types. Youll see this repeated later, with other types. And well cover traits fully
And well cover traits fully later in the book, Section 9. later in the book, Section 9.
## char ## char
Weve only worked with numbers so far, but what about letters? Weve only worked with numbers so far, but what about letters? Rusts most
Rusts most primitive alphabetic type is the `char`: primitive alphabetic type is the `char`:
```rust ```rust
fn main() { fn main() {
@ -428,18 +433,21 @@ fn main() {
} }
``` ```
Rusts `char` represents a [Unicode Scalar Value], which means that it can represent a lot more than just ASCII. Rusts `char` represents a [Unicode Scalar Value], which means that it can
“Character” isnt really a concept in Unicode, however: your human intutition for what a character is may not match up with a `char`. represent a lot more than just ASCII. “Character” isnt really a concept in
It also means that `char`s are four bytes each. Unicode, however: your human intutition for what a character is may not match
up with a `char`. It also means that `char`s are four bytes each.
[Unicode Scalar Value]: http://www.unicode.org/glossary/#unicode_scalar_value [Unicode Scalar Value]: http://www.unicode.org/glossary/#unicode_scalar_value
The single quotes are important: to define a literal single character, we use single quotes. The single quotes are important: to define a literal single character, we use
If we used double quotes, wed be defining a `&str`. Lets talk about that next! single quotes. If we used double quotes, wed be defining a `&str`. Lets talk
about that next!
## str ## str
We can declare literal strings with `"`s. Weve seen them already, with `println!`: We can declare literal strings with `"`s. Weve seen them already, with
`println!`:
```rust ```rust
fn main() { fn main() {
@ -451,8 +459,7 @@ fn main() {
} }
``` ```
String literals are immutable, and of a fixed length. String literals are immutable, and of a fixed length. Rust has a second string
Rust has a second string type, `String`, that well discuss in section 8. type, `String`, that well discuss in section 8.
`&str`s are UTF-8 encoded. `&str`s are UTF-8 encoded.

View File

@ -1,22 +1,22 @@
# Variable Bindings # Variable Bindings
The foundation of virtually every program is the ability to store and modify data. The foundation of virtually every program is the ability to store and modify
Rust programs are no different. data. Rust programs are no different. Lets start with a short example.
Lets start with a short example.
## The basics of bindings ## The basics of bindings
First, well generate a new project with Cargo. First, well generate a new project with Cargo. Open a terminal, and navigate
Open a terminal, and navigate to the directory where youd like to keep your projects. to the directory where youd like to keep your projects. From there, lets
From there, lets generate a new project: generate a new project:
```bash ```bash
$ cargo new --bin bindings $ cargo new --bin bindings
$ cd bindings $ cd bindings
``` ```
This creates a new project, bindings, and sets up our `Cargo.toml` and `src/main.rs` files. This creates a new project, bindings, and sets up our `Cargo.toml` and
As we saw in “Hello, World!”, Cargo will generate these files and create a little hello world program for us: `src/main.rs` files. As we saw in “Hello, World!”, Cargo will generate these
files and create a little hello world program for us:
```rust ```rust
fn main() { fn main() {
@ -43,16 +43,17 @@ $ cargo run
The value of x is: 5 The value of x is: 5
``` ```
If you see an error instead, double check that you have copied the program exactly as written. If you see an error instead, double check that you have copied the program
Lets break this down, line by line. exactly as written. Lets break this down, line by line.
```rust,ignore ```rust,ignore
fn main() { fn main() {
``` ```
The `main()` function is the entry point of every Rust program. The `main()` function is the entry point of every Rust program. Well talk more
Well talk more about functions in the next section, but for now, all we need to know is that this is where our program begins. about functions in the next section, but for now, all we need to know is that
The opening curly brace, `{`, indicates the start of the functions body. this is where our program begins. The opening curly brace, `{`, indicates the
start of the functions body.
```rust,ignore ```rust,ignore
let x = 5; let x = 5;
@ -67,9 +68,9 @@ let NAME = EXPRESSION;
``` ```
A `let` statement first evaluates the `EXPRESSION`, and then binds the A `let` statement first evaluates the `EXPRESSION`, and then binds the
resulting value to `NAME` so that it can be referred to later in the program. In resulting value to `NAME` so that it can be referred to later in the program.
our simple example, the expression was already a value, 5, but we could achieve In our simple example, the expression was already a value, 5, but we could
the same effect with: achieve the same effect with:
```rust ```rust
let x = 2 + 3; let x = 2 + 3;
@ -79,22 +80,24 @@ In general, `let` statements work with patterns; a name is a particularly
humble form of pattern. Patterns are a big part of Rust, well see more complex humble form of pattern. Patterns are a big part of Rust, well see more complex
and powerful patterns as we go along. and powerful patterns as we go along.
Before we do that, though, lets finish investigating this example. Before we do that, though, lets finish investigating this example. Heres the
Heres the next line: next line:
```rust,ignore ```rust,ignore
println!("The value of x is: {}", x); println!("The value of x is: {}", x);
``` ```
The `println!` macro prints text to the screen. The `println!` macro prints text to the screen. We can tell that its a macro
We can tell that its a macro due to the `!`. due to the `!`. We wont learn how to write macros until much later in the
We wont learn how to write macros until much later in the book, but well use macros provided by the standard library throughout. book, but well use macros provided by the standard library throughout. Every
Every time you see a `!`, remember that it signifies a macro. time you see a `!`, remember that it signifies a macro. Macros can add new
Macros can add new syntax to the language, and the `!` is a reminder that things may look slightly unusual. syntax to the language, and the `!` is a reminder that things may look slightly
unusual.
`println!`, specifically, has one required argument, a format string, and zero or more optional arguments. `println!`, specifically, has one required argument, a format string, and
The format string can contain the special text `{}`. zero or more optional arguments. The format string can contain the special text
Each instance of `{}` corresponds to an additional argument. Heres an example: `{}`. Each instance of `{}` corresponds to an additional argument. Heres an
example:
```rust ```rust
let x = 2 + 3; let x = 2 + 3;
@ -102,14 +105,16 @@ let y = x + 5;
println!("The value of x is {}, and the value of y is {}", x, y); println!("The value of x is {}, and the value of y is {}", x, y);
``` ```
You can think of `{}` as little crab pincers, holding the value in place. You can think of `{}` as little crab pincers, holding the value in place. This
This placeholder has a number of more advanced formatting options that well discuss later. placeholder has a number of more advanced formatting options that well discuss
later.
```rust,ignore ```rust,ignore
} }
``` ```
Finally, a closing curly brace matches up with the opening curly brace that declared the `main()` function, and declares its end. Finally, a closing curly brace matches up with the opening curly brace that
declared the `main()` function, and declares its end.
This explains our output: This explains our output:
@ -117,12 +122,12 @@ This explains our output:
The value of x is: 5 The value of x is: 5
``` ```
We assign `5` to a binding, `x`, and then print it to the screen with `println!`. We assign `5` to a binding, `x`, and then print it to the screen with
`println!`.
## Multiple binding ## Multiple binding
Lets try a more complex pattern. Lets try a more complex pattern. Change our example program to this:
Change our example program to this:
```rust ```rust
fn main() { fn main() {
@ -143,8 +148,7 @@ The value of x is: 5
The value of y is: 6 The value of y is: 6
``` ```
Weve created two bindings with one `let`! Weve created two bindings with one `let`! Heres our pattern:
Heres our pattern:
```text ```text
(x, y) (x, y)
@ -156,8 +160,8 @@ And heres the value:
(5, 6) (5, 6)
``` ```
As you can see, the two line up visually, and so `let` binds `5` to `x` and `6` to `y`. As you can see, the two line up visually, and so `let` binds `5` to `x` and `6`
We could have used two `let` statements as well: to `y`. We could have used two `let` statements as well:
```rust ```rust
fn main() { fn main() {
@ -166,15 +170,18 @@ fn main() {
} }
``` ```
In simple cases like this, two `let`s may be clearer, but in others, creating multiple bindings at once is nice. In simple cases like this, two `let`s may be clearer, but in others, creating
As we become more proficient in Rust, well figure out which style is better, but its mostly a judgement call. multiple bindings at once is nice. As we become more proficient in Rust, well
figure out which style is better, but its mostly a judgement call.
## Type annotations ## Type annotations
You may have noticed that we didnt declare the type of `x` or `y` in our previous examples. You may have noticed that we didnt declare the type of `x` or `y` in our
Rust is a *statically typed* language, which means that at compile time, we must know the types of all bindings. previous examples. Rust is a *statically typed* language, which means that at
But annotating every single binding with a type can feel like busywork, and make code noisy. compile time, we must know the types of all bindings. But annotating every
To solve this issue, Rust uses type inference, meaning that it attempts to infer the types of your bindings. single binding with a type can feel like busywork, and make code noisy. To
solve this issue, Rust uses type inference, meaning that it attempts to infer
the types of your bindings.
The primary way that the type is inferred is by looking at how it is used. The primary way that the type is inferred is by looking at how it is used.
Lets look at the example again: Lets look at the example again:
@ -186,8 +193,8 @@ fn main() {
``` ```
When we bind `x` to `5`, the compiler knows that `x` should be a numeric type. When we bind `x` to `5`, the compiler knows that `x` should be a numeric type.
Without any other information, it defaults to `i32`, a thirty-two bit integer type. Without any other information, it defaults to `i32`, a thirty-two bit integer
Well talk more about Rusts basic types in section 3.3. type. Well talk more about Rusts basic types in section 3.3.
Heres what a `let` statement with a type annotation looks like: Heres what a `let` statement with a type annotation looks like:
@ -197,15 +204,15 @@ fn main() {
} }
``` ```
We can add a colon, followed by the type name. We can add a colon, followed by the type name. Heres the structure of a `let`
Heres the structure of a `let` statement with a type annotation: statement with a type annotation:
```text ```text
let PATTERN: TYPE = VALUE; let PATTERN: TYPE = VALUE;
``` ```
Note that the colon and the `TYPE` go _after_ the `PATTERN`, not in the pattern itself. Note that the colon and the `TYPE` go _after_ the `PATTERN`, not in the pattern
As an example, heres our more complex pattern with two bindings: itself. As an example, heres our more complex pattern with two bindings:
```rust ```rust
fn main() { fn main() {
@ -213,11 +220,13 @@ fn main() {
} }
``` ```
Just like we match up the `VALUE` with the `PATTERN`, we match up the `TYPE` with the `PATTERN`. Just like we match up the `VALUE` with the `PATTERN`, we match up the `TYPE`
with the `PATTERN`.
## Delayed Initialization ## Delayed Initialization
We do not have to provide bindings with an initial value, and can assign it later. Try this program: We do not have to provide bindings with an initial value, and can assign it
later. Try this program:
```rust ```rust
fn main() { fn main() {
@ -238,9 +247,9 @@ $ cargo run
The value of x is: 5 The value of x is: 5
``` ```
Its all good. Its all good. This raises a question, though: what if we try to print out a
This raises a question, though: what if we try to print out a binding before we declare a value? binding before we declare a value? Heres a program that demonstrates this
Heres a program that demonstrates this question: question:
```rust,ignore ```rust,ignore
fn main() { fn main() {
@ -269,14 +278,14 @@ Could not compile `bindings`.
To learn more, run the command again with --verbose. To learn more, run the command again with --verbose.
``` ```
An error! An error! The compiler wont let us write a program like this. This is our
The compiler wont let us write a program like this. first example of the compiler helping us find an error in our program.
This is our first example of the compiler helping us find an error in our program. Different programming languages have different ways of approaching this
Different programming languages have different ways of approaching this problem. problem. Some languages always initialize values with some sort of default.
Some languages always initialize values with some sort of default. Other languages leave the value uninitialized, and make no promises about what
Other languages leave the value uninitialized, and make no promises about what happens if you try to use something before initialization. happens if you try to use something before initialization. Rust chooses
Rust chooses something else: error and force the programmer to explain what they want. something else: error and force the programmer to explain what they want. We
We must do some sort of initialization before we can use `x`. must do some sort of initialization before we can use `x`.
### Extended error explanations ### Extended error explanations
@ -287,9 +296,9 @@ src/main.rs:4:39: 4:40 help: run `rustc --explain E0381` to see a detailed expla
``` ```
We can see an extended explanation by passing the `--explain` flag to `rustc`. We can see an extended explanation by passing the `--explain` flag to `rustc`.
Not every error has a longer explanation, but many of them do. Not every error has a longer explanation, but many of them do. These extended
These extended explanations try to show off common ways that the error occurs, and common solutions to the issue. explanations try to show off common ways that the error occurs, and common
Heres `E0381`: solutions to the issue. Heres `E0381`:
```bash ```bash
$ rustc --explain E0381 $ rustc --explain E0381
@ -303,12 +312,13 @@ To fix this, ensure that any declared variables are initialized before being
used. used.
``` ```
These explanations can really help if youre stuck on an error. These explanations can really help if youre stuck on an error. The compiler is
The compiler is your friend, and is here to help. your friend, and is here to help.
## Mutable bindings ## Mutable bindings
What about changing the value of a binding? Heres another sample program that asks this question: What about changing the value of a binding? Heres another sample program that
asks this question:
```rust,ignore ```rust,ignore
fn main() { fn main() {
@ -334,11 +344,10 @@ src/main.rs:2 let x = 5;
^ ^
``` ```
The error mentions `re-assigment of immutable variable`. The error mentions `re-assigment of immutable variable`. Thats right: bindings
Thats right: bindings are immutable. are immutable. But theyre only immutable by default. In a pattern, when were
But theyre only immutable by default. creating a new name, we can add `mut` in front to make the binding a mutable
In a pattern, when were creating a new name, we can add `mut` in front to make the binding a mutable one. one. Heres an example:
Heres an example:
```rust ```rust
fn main() { fn main() {
@ -362,9 +371,9 @@ The value of x is: 5
The value of x is: 6 The value of x is: 6
``` ```
We can now change the value that `x` binds to. We can now change the value that `x` binds to. Note that the syntax is not `let
Note that the syntax is not `let mut` exactly; its using `mut` in a pattern. mut` exactly; its using `mut` in a pattern. This becomes more obvious with our
This becomes more obvious with our `()` pattern: `()` pattern:
```rust,ignore ```rust,ignore
@ -390,13 +399,13 @@ src/main.rs:2 let (mut x, y) = (5, 6);
^ ^
``` ```
Its fine with re-assigning `x`, but not `y`. Its fine with re-assigning `x`, but not `y`. The `mut` only applies to the
The `mut` only applies to the name that follows it, not the whole pattern. name that follows it, not the whole pattern.
### Reassignment, not mutation ### Reassignment, not mutation
There is one subtlety we havent covered yet: `mut` allows you to mutate _the binding_, but not _what the binding binds to_. There is one subtlety we havent covered yet: `mut` allows you to mutate _the
In other words: binding_, but not _what the binding binds to_. In other words:
```rust ```rust
fn main() { fn main() {
@ -406,18 +415,19 @@ fn main() {
} }
``` ```
This is not changing the value that `x` is bound to, but creating a new value, `6`, and changing the binding to bind to it instead. This is not changing the value that `x` is bound to, but creating a new value,
Its a subtle but important difference. `6`, and changing the binding to bind to it instead. Its a subtle but
Well, for now, it does not make a lot of difference, but when our programs get more complex, it will. important difference. Well, for now, it does not make a lot of difference, but
Specifically, passing arguments to functions will illustrate the difference. when our programs get more complex, it will. Specifically, passing arguments to
Well talk about that in the next section, when we discuss functions. functions will illustrate the difference. Well talk about that in the next
section, when we discuss functions.
## Scope ## Scope
Variable bindings have a scope in which theyre valid. Variable bindings have a scope in which theyre valid. That scope begins from
That scope begins from the point at which the binding is declared, and ends at the end of the next block of code. the point at which the binding is declared, and ends at the end of the next
We can only access bindings which are in scope. block of code. We can only access bindings which are in scope. We cannot
We cannot access them before they come into scope or after they go out of scope. access them before they come into scope or after they go out of scope.
Heres an example: Heres an example:
```rust ```rust
@ -459,12 +469,13 @@ fn main() {
} }
``` ```
What bindings are in and out of scope will become much more important later, once we learn about references and traits. What bindings are in and out of scope will become much more important later,
once we learn about references and traits.
## Shadowing ## Shadowing
A final thing about bindings: they can shadow previous bindings with the same name. A final thing about bindings: they can shadow previous bindings with the same
Heres a sample program: name. Heres a sample program:
```rust ```rust
fn main() { fn main() {
@ -485,14 +496,13 @@ src/main.rs:2 let x = 5;
The value of x is: 6 The value of x is: 6
``` ```
There are two interesting things in this output. There are two interesting things in this output. First, Rust will compile and
First, Rust will compile and run this program, no problem. run this program, no problem. And as we can see, the value of `x` is `6`. But
And as we can see, the value of `x` is `6`. we didnt declare `x` as mutable. Instead, we declared a _new_ binding that is
But we didnt declare `x` as mutable. _also_ named `x`, and gave it a new value. The older value that we bound `x` to
Instead, we declared a _new_ binding that is _also_ named `x`, and gave it a new value. is inaccessible as soon as the new `x` is declared. This can be useful if youd
The older value that we bound `x` to is inaccessible as soon as the new `x` is declared. like to perform a few transformations on a value, and leave it immutable. For
This can be useful if youd like to perform a few transformations on a value, and leave it immutable. example:
For example:
```rust ```rust
fn main() { fn main() {
@ -512,10 +522,10 @@ This will print:
The value of x is: 12 The value of x is: 12
``` ```
This lets us modify `x`, but not deal with mutation. This lets us modify `x`, but not deal with mutation. This is nice because we
This is nice because we know that the compiler will let us know if we try to modify it later. know that the compiler will let us know if we try to modify it later. Lets
Lets assume that after we calculate `12`, we dont want to modify `x` again. assume that after we calculate `12`, we dont want to modify `x` again. If we
If we had written this program in a mutable style, like this: had written this program in a mutable style, like this:
``` ```
fn main() { fn main() {
@ -531,8 +541,8 @@ fn main() {
} }
``` ```
Rust is happy to let us mutate it again, to `15`. Rust is happy to let us mutate it again, to `15`. A similar program in our
A similar program in our immutable style will let us know about that accidental mutation, however: immutable style will let us know about that accidental mutation, however:
```rust,ignore ```rust,ignore
fn main() { fn main() {
@ -566,10 +576,11 @@ Could not compile `bindings`.
Exactly what we wanted. Exactly what we wanted.
Shadowing can take some time to get used to, but its very powerful, and works well with immutability. Shadowing can take some time to get used to, but its very powerful, and works
well with immutability.
There was one more thing we should talk about in the output from compiling our initial program. There was one more thing we should talk about in the output from compiling our
Its this part: initial program. Its this part:
```text ```text
src/main.rs:2:9: 2:10 warning: unused variable: `x`, #[warn(unused_variables)] on by default src/main.rs:2:9: 2:10 warning: unused variable: `x`, #[warn(unused_variables)] on by default
@ -583,20 +594,21 @@ let x = 6;
``` ```
Rust knows that we shadowed `x`, but we never ended up using the initial value. Rust knows that we shadowed `x`, but we never ended up using the initial value.
This isnt _wrong_, exactly, it just may not have been what we wanted. This isnt _wrong_, exactly, it just may not have been what we wanted. In this
In this case, the compiler issues a warning, but still compiles our program. case, the compiler issues a warning, but still compiles our program. The
The `#[warn(unused_variables)]` syntax is called an attribute, which well discuss in a later section. `#[warn(unused_variables)]` syntax is called an attribute, which well
More specifically, a warning like this is called a lint, which is an old term for the bits of sheeps wool that you wouldnt want to put in cloth. discuss in a later section. More specifically, a warning like this is called a
Similarly, this lint is telling us that we may have an extra bit of code we dont need. lint, which is an old term for the bits of sheeps wool that you wouldnt
Our program would work just fine without it. want to put in cloth. Similarly, this lint is telling us that we may have an
extra bit of code we dont need. Our program would work just fine without it.
Its worth listening to these warnings, and fixing the problems they point out. Its worth listening to these warnings, and fixing the problems they point out.
They can be signs of a larger problem. They can be signs of a larger problem. In this case, we may not have realized
In this case, we may not have realized that we were shadowing `x`. that we were shadowing `x`.
### Shadowing and scopes ### Shadowing and scopes
Like any binding, a binding that shadows another binding will go away at the end of a scope. Like any binding, a binding that shadows another binding will go away at the
Heres an example program: end of a scope. Heres an example program:
```rust ```rust
fn main() { fn main() {