2016-01-09 01:09:26 +08:00
# Up and Running
We’ ll start our journey with Rust by talking about the absolute basics —
concepts that appear in almost every programming language. Many programming
languages have lots in common at their core. None of the concepts presented are
unique to Rust, but we’ ll cover Rust’ s particular syntax and conventions around
these common concepts.
If you want to skip this section, you can, but you may end up coming back later
to find out small details. These foundations will be in every single useful
Rust program, and learning them gives us a strong core to start from.
# Variable Bindings
The foundation of virtually every program is the ability to store and modify
data. Rust programs are no different. Let’ s start with a short example.
## The basics of bindings
First, we’ ll generate a new project with Cargo. Open a terminal, and navigate
to the directory where you’ d like to keep your projects. From there, let’ s
generate a new project:
```bash
$ cargo new --bin bindings
$ cd bindings
```
This creates a new project, ‘ bindings’ , and sets up our `Cargo.toml` and
`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
fn main() {
println!("Hello, world!");
}
```
Let’ s replace that program with this one:
```rust
fn main() {
let x = 5;
println!("The value of x is: {}", x);
}
```
And finally, run it:
```bash
$ cargo run
Compiling bindings v0.1.0 (file:///projects/bindings)
Running `target/debug/bindings`
The value of x is: 5
```
If you see an error instead, double check that you have copied the program
exactly as written. Let’ s break this down, line by line.
```rust,ignore
fn main() {
```
The `main()` function is the entry point of every Rust program. We’ ll talk more
about functions in the next section, but for now, all we need to know is that
this is where our program begins. The opening curly brace, `{` , indicates the
start of the function’ s body.
```rust,ignore
let x = 5;
```
This is our first ‘ variable binding’ , which we create with a ‘ `let` statement’ .
This `let` statement has this form:
```text
let NAME = EXPRESSION;
```
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 our simple example, the expression was already a value, 5, but we could
achieve the same effect with:
```rust
let x = 2 + 3;
```
In general, `let` statements work with patterns; a name is a particularly
humble form of pattern. Patterns are a big part of Rust, we’ ll see more complex
and powerful patterns as we go along.
Before we do that, though, let’ s finish investigating this example. Here’ s the
next line:
```rust,ignore
println!("The value of x is: {}", x);
```
The `println!` macro prints text to the screen. We can tell that it’ s a macro
due to the `!` . We won’ t learn how to write macros until much later in the
book, but we’ ll use macros provided by the standard library throughout. Every
time you see a `!` , remember that it signifies a macro. Macros can add new
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. The format string can contain the special text
`{}` . Each instance of `{}` corresponds to an additional argument. Here’ s an
example:
```rust
let x = 2 + 3;
let y = x + 5;
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. This
placeholder has a number of more advanced formatting options that we’ ll discuss
later.
```rust,ignore
}
```
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:
```text
The value of x is: 5
```
We assign `5` to a binding, `x` , and then print it to the screen with
`println!` .
## Multiple binding
Let’ s try a more complex pattern. Change our example program to this:
```rust
fn main() {
let (x, y) = (5, 6);
println!("The value of x is: {}", x);
println!("The value of y is: {}", y);
}
```
And run it with `cargo run` :
```text
$ cargo run
Compiling bindings v0.1.0 (file:///projects/bindings)
Running `target/debug/bindings`
The value of x is: 5
The value of y is: 6
```
We’ ve created two bindings with one `let` ! Here’ s our pattern:
```text
(x, y)
```
And here’ s the value:
```text
(5, 6)
```
As you can see, the two line up visually, and so `let` binds `5` to `x` and `6`
to `y` . We could have used two `let` statements as well:
```rust
fn main() {
let x = 5;
let y = 6;
}
```
In simple cases like this, two `let` s may be clearer, but in others, creating
multiple bindings at once is nice. As we become more proficient in Rust, we’ ll
figure out which style is better, but it’ s mostly a judgement call.
## Type annotations
You may have noticed that we didn’ t declare the type of `x` or `y` in our
previous examples. Rust is a *statically typed* language, which means that at
compile time, we must know the types of all bindings. But annotating every
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.
Let’ s look at the example again:
```rust
fn main() {
let x = 5;
}
```
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. We’ ll talk more about Rust’ s basic types in section 3.3.
Here’ s what a `let` statement with a ‘ type annotation’ looks like:
```rust
fn main() {
let x: i32 = 5;
}
```
We can add a colon, followed by the type name. Here’ s the structure of a `let`
statement with a type annotation:
```text
let PATTERN: TYPE = VALUE;
```
Note that the colon and the `TYPE` go _after_ the `PATTERN` , not in the pattern
itself. As an example, here’ s our more complex pattern with two bindings:
```rust
fn main() {
let (x, y): (i32, i32) = (5, 6);
}
```
Just like we match up the `VALUE` with the `PATTERN` , we match up the `TYPE`
with the `PATTERN` .
## Delayed Initialization
We do not have to provide bindings with an initial value, and can assign it
later. Try this program:
```rust
fn main() {
let x;
x = 5;
println!("The value of x is: {}", x);
}
```
And run it with `cargo run` :
```text
$ cargo run
Compiling bindings v0.1.0 (file:///projects/bindings)
Running `target/debug/bindings`
The value of x is: 5
```
It’ s all good. This raises a question, though: what if we try to print out a
binding before we declare a value? Here’ s a program that demonstrates this
question:
```rust,ignore
fn main() {
let x;
println!("The value of x is: {}", x);
x = 5;
}
```
We can find out the answer with `cargo run` :
```text
Compiling bindings v0.1.0 (file:///projects/bindings)
src/main.rs:4:39: 4:40 error: use of possibly uninitialized variable: `x` [E0381]
src/main.rs:4 println!(“The value of x is: {}”, x);
^
< std macros > :2:25: 2:56 note: in this expansion of format_args!
< std macros > :3:1: 3:54 note: in this expansion of print! (defined in < std macros > )
src/main.rs:4:5: 4:42 note: in this expansion of println! (defined in < std macros > )
src/main.rs:4:39: 4:40 help: run `rustc --explain E0381` to see a detailed explanation
error: aborting due to previous error
Could not compile `bindings` .
To learn more, run the command again with --verbose.
```
An error! The compiler won’ t let us write a program like this. 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
problem. Some languages always initialize values with some sort of default.
Other languages leave the value uninitialized, and make no promises about what
happens if you try to use something before initialization. Rust chooses
something else: error and force the programmer to explain what they want. We
must do some sort of initialization before we can use `x` .
### Extended error explanations
There’ s one more interesting part of this error message:
```text
src/main.rs:4:39: 4:40 help: run `rustc --explain E0381` to see a detailed explanation
```
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. These extended
explanations try to show off common ways that the error occurs, and common
solutions to the issue. Here’ s `E0381` :
```bash
$ rustc --explain E0381
It is not allowed to use or capture an uninitialized variable. For example:
fn main() {
let x: i32;
let y = x; // error, use of possibly uninitialized variable
To fix this, ensure that any declared variables are initialized before being
used.
```
These explanations can really help if you’ re stuck on an error. The compiler is
your friend, and is here to help.
## Mutable bindings
What about changing the value of a binding? Here’ s another sample program that
asks this question:
```rust,ignore
fn main() {
let x = 5;
x = 6;
println!("The value of x is: {}", x);
}
```
`cargo run` has the answer for us:
```bash
$ cargo run
Compiling bindings v0.1.0 (file:///projects/bindings)
src/main.rs:4:5: 4:10 error: re-assignment of immutable variable `x` [E0384]
src/main.rs:4 x = 6;
^~~~~
src/main.rs:4:5: 4:10 help: run `rustc --explain E0384` to see a detailed explanation
src/main.rs:2:9: 2:10 note: prior assignment occurs here
src/main.rs:2 let x = 5;
^
```
The error mentions `re-assigment of immutable variable` . That’ s right: bindings
are immutable. But they’ re only immutable by default. In a pattern, when we’ re
creating a new name, we can add `mut` in front to make the binding a mutable
one. Here’ s an example:
```rust
fn main() {
let mut x = 5;
println!("The value of x is: {}", x);
x = 6;
println!("The value of x is: {}", x);
}
```
Running this, we get:
```bash
$ cargo run
Compiling bindings v0.1.0 (file:///projects/bindings)
Running `target/debug/bindings`
The value of x is: 5
The value of x is: 6
```
We can now change the value that `x` binds to. Note that the syntax is not `let
mut` exactly; it’ s using `mut` in a pattern. This becomes more obvious with our
`()` pattern:
```rust,ignore
fn main() {
let (mut x, y) = (5, 6);
x = 7;
y = 8;
}
```
The compiler will complain about this program:
```bash
$ cargo build
Compiling bindings v0.1.0 (file:///projects/bindings)
src/main.rs:5:5: 5:10 error: re-assignment of immutable variable `y` [E0384]
src/main.rs:5 y = 8;
^~~~~
src/main.rs:5:5: 5:10 help: run `rustc --explain E0384` to see a detailed explanation
src/main.rs:2:17: 2:18 note: prior assignment occurs here
src/main.rs:2 let (mut x, y) = (5, 6);
^
```
It’ s fine with re-assigning `x` , but not `y` . The `mut` only applies to the
name that follows it, not the whole pattern.
### Reassignment, not mutation
There is one subtlety we haven’ t covered yet: `mut` allows you to mutate _the
binding_, but not _what the binding binds to_ . In other words:
```rust
fn main() {
let mut x = 5;
x = 6;
}
```
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. It’ s a subtle but
important difference. Well, for now, it does not make a lot of difference, but
when our programs get more complex, it will. Specifically, passing arguments to
functions will illustrate the difference. We’ ll talk about that in the next
section, when we discuss functions.
## Scope
Variable bindings have a ‘ scope’ in which they’ re valid. That scope begins from
the point at which the binding is declared, and ends at the end of the next
block of code. We can only access bindings which are ‘ in scope’ . We cannot
access them ‘ before they come into scope’ or ‘ after they go out of scope’ .
Here’ s an example:
```rust
fn main() {
println!("x is not yet in scope");
let x = 5;
println!("x is now in scope");
println!("In real code, we’ d now do a bunch of work.");
println!("x will go out of scope now! The next curly brace is ending the main function.");
}
```
We can create arbitrary scopes through the use of `{` and `}` :
```rust
fn main() {
println!("x is not yet in scope");
let x = 5;
println!("x is now in scope");
println!("Let’ s start a new scope!");
{
let y = 5;
println!("y is now in scope");
println!("x is also still in scope");
println!("y will go out of scope now!");
println!("The next curly brace is ending the scope we started.");
}
println!("x is still in scope, but y is now out of scope and is not usable");
println!("x will go out of scope now! The next curly brace is ending the main function.");
}
```
What bindings are in and out of scope will become much more important later,
once we learn about ‘ references’ and ‘ traits’ .
## Shadowing
A final thing about bindings: they can ‘ shadow’ previous bindings with the same
name. Here’ s a sample program:
```rust
fn main() {
let x = 5;
let x = 6;
println!("The value of x is: {}", x);
}
```
Running it, we can see the shadowing in action:
```text
src/main.rs:2:9: 2:10 warning: unused variable: `x` , #[warn(unused_variables)] on by default
src/main.rs:2 let x = 5;
^
Running `target/debug/bindings`
The value of x is: 6
```
There are two interesting things in this output. First, Rust will compile and
run this program, no problem. And as we can see, the value of `x` is `6` . But
we didn’ t declare `x` as mutable. Instead, we declared a _new_ binding that is
_also_ named `x` , and gave it a new value. The older value that we bound `x` to
is inaccessible as soon as the new `x` is declared. This can be useful if you’ d
like to perform a few transformations on a value, and leave it immutable. For
example:
```rust
fn main() {
let x = 5;
let x = x + 1;
let x = x * 2;
println!("The value of x is: {}", x);
}
```
This will print:
```bash
Compiling bindings v0.1.0 (file:///projects/bindings)
Running `target/debug/bindings`
The value of x is: 12
```
This lets us modify `x` , but not deal with mutation. This is nice because we
know that the compiler will let us know if we try to modify it later. Let’ s
assume that after we calculate `12` , we don’ t want to modify `x` again. If we
had written this program in a mutable style, like this:
2016-01-14 12:53:34 +08:00
```rust
2016-01-09 01:09:26 +08:00
fn main() {
let mut x = 5;
x = x + 1;
x = x * 2;
println!("The value of x is: {}", x);
x = 15;
println!("The value of x is: {}", x);
}
```
Rust is happy to let us mutate it again, to `15` . A similar program in our
immutable style will let us know about that accidental mutation, however:
```rust,ignore
fn main() {
let x = 5;
let x = x + 1;
let x = x * 2;
println!("The value of x is: {}", x);
x = 15;
println!("The value of x is: {}", x);
}
```
If we try to compile, we get an error:
```bash
$ cargo build
Compiling bindings v0.1.0 (file:///projects/bindings)
src/main.rs:8:5: 8:11 error: re-assignment of immutable variable `x` [E0384]
src/main.rs:8 x = 15;
^~~~~~
src/main.rs:8:5: 8:11 help: run `rustc --explain E0384` to see a detailed explanation
src/main.rs:4:9: 4:10 note: prior assignment occurs here
src/main.rs:4 let x = x * 2;
^
error: aborting due to previous error
Could not compile `bindings` .
```
Exactly what we wanted.
Shadowing can take some time to get used to, but it’ s very powerful, and works
well with immutability.
There was one more thing we should talk about in the output from compiling our
initial program. It’ s this part:
```text
src/main.rs:2:9: 2:10 warning: unused variable: `x` , #[warn(unused_variables)] on by default
```
Here’ s the two lines of relevant code:
```rust
let x = 5;
let x = 6;
```
Rust knows that we shadowed `x` , but we never ended up using the initial value.
This isn’ t _wrong_ , exactly, it just may not have been what we wanted. In this
case, the compiler issues a ‘ warning’ , but still compiles our program. The
`#[warn(unused_variables)]` syntax is called an ‘ attribute’ , which we’ ll
discuss in a later section. More specifically, a warning like this is called a
‘ lint’ , which is an old term for the bits of sheep’ s wool that you wouldn’ t
want to put in cloth. Similarly, this lint is telling us that we may have an
extra bit of code we don’ t need. Our program would work just fine without it.
It’ s worth listening to these warnings, and fixing the problems they point out.
They can be signs of a larger problem. In this case, we may not have realized
that we were shadowing `x` .
### Shadowing and scopes
Like any binding, a binding that shadows another binding will go away at the
end of a scope. Here’ s an example program:
```rust
fn main() {
let x = 5;
println!("Before shadowing, x is: {}", x);
{
let x = 6;
println!("Now that x is shadowed, x is: {}", x);
}
println!("After shadowing, x is: {}", x);
}
```
If we run this example, we can see the shadow appear and disappear:
```bash
$ cargo run
Compiling bindings v0.1.0 (file:///projects/bindings)
Running `target/debug/bindings`
Before shadowing, x is: 5
Now that x is shadowed, x is: 6
After shadowing, x is: 5
```
# Functions
Functions are pervasive in Rust code. We’ ve already seen the most important
function, `main()` , in previous sections of the book:
```rust
fn main() {
println!("Hello, world!");
}
```
We can declare new functions with the `fn` keyword:
```rust
fn another_function() {
println!("Another function.");
}
```
Rust code uses `snake_case` as a style for function names: all lower case, with
underscores separating words. (It also uses them for variable names, too.) We
can can call any function we’ ve defined by using its name and some parentheses:
```rust
fn main() {
println!("Hello, world!");
another_function();
}
fn another_function() {
println!("Another function.");
}
```
Let’ s start a new project to explore functions. Open a terminal, and navigate
to the directory where you’ d like to keep your projects. From there, use Cargo
to generate a new project:
```bash
$ cargo new --bin functions
$ cd functions
```
Place the new example in `src/main.rs` , and run it:
```bash
$ cargo run
Compiling functions v0.1.0 (file:///projects/functions)
Running `target/debug/functions`
Hello, world!
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. It then prints its
message as well.
## Function Arguments
Functions can also take arguments:
```rust
fn main() {
another_function(5);
}
fn another_function(x: i32) {
println!("The value of x is: {}", x);
}
```
Let’ s try running it:
```bash
$ cargo run
Compiling functions v0.1.0 (file:///projects/functions)
Running `target/debug/functions`
The value of x is: 5
```
Let’ s take a closer look at `another_function()` ’ s signature:
```rust,ignore
fn another_function(x: i32) {
```
Declaring a function which takes a single argument looks like this:
```text
fn NAME(PATTERN: TYPE) {
```
That’ s right, patterns appear again. Consider how the parameter declaration
here looks like the `let` bindings we used earlier:
```rust,ignore
let x: i32;
fn another_function(x: i32) {
```
There’ s only one difference here: in function signatures, we _must_ declare the
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:
```text
fn NAME(PATTERN, PATTERN, PATTERN, PATTERN...) {
```
Here’ s a full example:
```rust
fn main() {
another_function(5, 6);
}
fn another_function(x: i32, y: i32) {
println!("The value of x is: {}", x);
println!("The value of y is: {}", y);
}
```
Let’ s try it:
```bash
$ cargo run
Compiling functions v0.1.0 (file:///projects/functions)
Running `target/debug/functions`
The value of x is: 5
The value of y is: 6
```
We could also create bindings, and pass them in as arguments:
```rust
fn main() {
let a = 5;
let b = 6;
another_function(a, b);
}
fn another_function(x: i32, y: i32) {
println!("The value of x is: {}", x);
println!("The value of y is: {}", y);
}
```
This has the same effect:
```bash
$ cargo run
Compiling functions v0.1.0 (file:///projects/functions)
Running `target/debug/functions`
The value of x is: 5
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` . Inside a function,
only its parameters are in scope, so we need to use those names. Bindings
passed as parameters don’ t need to have the same name as the arguments.
## Return values
Functions can also return values back to the function that called them:
```TEXT
fn NAME(PATTERN, PATTERN, PATTERN, PATTERN...) -> TYPE {
```
We don’ t name return values, but we do declare their type, after an arrow:
`->` . Here’ s a sample program:
```rust
fn main() {
let x = five();
println!("The value of x is: {}", x);
}
fn five() -> i32 {
5
}
```
Let’ s try running it:
```bash
$ cargo run
Compiling functions v0.1.0 (file:///projects/functions)
Running `target/debug/functions`
The value of x is: 5
```
Let’ s examine this in more detail. There are two important bits. First, we can
use the return value of a function to initialize a binding:
```rust,ignore
let x = five();
```
Because `five()` returns a `5` , this is the same as:
```rust
let x = 5;
```
The second interesting bit is `five()` itself:
```rust
fn five() -> i32 {
5
}
```
We have no arguments, and our return type, `i32` . However, the body of this
function is a lonely `5` . There’ s a detail here that you may or may not have
noticed: we’ ve ended almost every line in our programs with a semicolon.
There’ s no semicolon here, though. Why not?
The answer to this question is:
> The return value of a function is the value of its final expression.
We haven’ t talked about expressions yet, so this definition doesn’ t help a lot.
Let’ s go over that now.
## Statements and Expressions
Expressions are bits of code that evaluate to a value. Consider some math
operations, like this:
```rust,ignore
5 + 6
```
We can evaluate this expression, and come up with a value: `11` . In Rust, most
bits of code are expressions. For example, calling a function is an expression:
```rust,ignore
foo(5)
```
The value is equal to whatever the return value of `foo()` is.
So why does this matter? Well, not everything is an expression. Some things are
‘ statements’ . Expressions _compute_ something, but statements _bind_ or _do_
something. It’ s a subtle difference. We’ ve already seen two kinds of
statements: `let` statements, and `fn` declarations.
Because `let` is a statement, not an expression, you can’ t assign it to another
binding. Here’ s an example that doesn’ t work:
```rust,ignore
fn main() {
let x = (let y = 6);
}
```
If we try to run this program, we’ ll get an error:
```bash
$ cargo run
Compiling functions v0.1.0 (file:///projects/functions)
src/main.rs:2:14: 2:17 error: expected identifier, found keyword `let`
src/main.rs:2 let x = (let y = 6);
^~~
src/main.rs:2:18: 2:19 error: expected one of `!` , `)` , `,` , `.` , `::` , `{` , or an operator, found `y`
src/main.rs:2 let x = (let y = 6);
^
Could not compile `functions` .
```
We also cannot somehow assign a `fn` declaration to a binding, either.
So what’ s this have to do with return values? Well, `{}` , a ‘ block’ that we
used earlier to create new scopes, _is_ an expression. Let’ s take a closer look
at `{}` . It looks like this:
```text
{
STATEMENT*
EXPRESSION
}
```
The `*` there means ‘ zero or more’ , so we can have any number of statements
followed by an expression. Since blocks are expressions themselves, we can nest
blocks inside of blocks. And since they return a value, we can use them in
`let` statements:
```rust
fn main() {
let x = 5;
let y = {
let z = 1;
x + z + 5
};
println!("The value of y is: {}", y);
}
```
Let’ s try running this program:
```bash
Compiling functions v0.1.0 (file:///projects/functions)
Running `target/debug/functions`
The value of y is: 11
```
We’ re now using a block to give us a value for `y` :
```rust,ignore
let y = {
};
```
Since the block can contain statements, we create a new variable binding, `z` ,
and give it a value. We then do some math for the final expression of the
block:
```rust,ignore
{
let z = 1;
x + z + 5
}
```
`5 + 1 + 5` is `11` , and so the value of the entire block is `11` . This gets
substituted into our `let` statement for `y` :
```rust,ignore
let y = 11;
```
Hence our output saying `y` is `11` .
Where else do we use blocks? As the body of functions! They’ re very similar:
```rust
fn main() {
let x = 5;
let y = {
x + 1
};
println!("The value of y is: {}", y);
let y = plus_one(x);
println!("The value of y is: {}", y);
}
fn plus_one(x: i32) -> i32 {
x + 1
}
```
Running this gives:
```bash
$ cargo run
Compiling functions v0.1.0 (file:///projects/functions)
Running `target/debug/functions`
The value of y is: 6
The value of y is: 6
```
In both cases, we use a block to produce a value. In the first case, it’ s
assigning with `let` :
```rust,ignore
let y = {
```
In the second, it’ s the return value of the function:
```rust,ignore
fn plus_one(x: i32) -> i32 {
```
### Expression statements
There’ s one more detail about expressions and statements: a semicolon takes any
expression, and turns it into a statement. Let’ s accidentally cause an error
with `plus_one()` :
```rust,ignore
fn main() {
let x = plus_one(5);
println!("The value of x is: {}", x);
}
fn plus_one(x: i32) -> i32 {
x + 1;
}
```
Instead of an expression, `x + 1` , we’ ve now turned it into a statement,
`x + 1;` .
Running this gives an error:
```bash
$ cargo run
Compiling functions v0.1.0 (file:///projects/functions)
src/main.rs:7:1: 9:2 error: not all control paths return a value [E0269]
src/main.rs:7 fn plus_one(x: i32) -> i32 {
src/main.rs:8 x + 1;
src/main.rs:9 }
src/main.rs:7:1: 9:2 help: run `rustc --explain E0269` to see a detailed explanation
src/main.rs:8:10: 8:11 help: consider removing this semicolon:
src/main.rs:8 x + 1;
^
error: aborting due to previous error
Could not compile `functions` .
```
Rust has our back here: it even suggests removing the semicolon, which fixes
the error. But the main error message is the core of the issue: statements
don’ t evaluate to a value, yet we want to return an `i32` .
In practice, Rust programmers don’ t often think about these rules at this
level. Usually, you have a semicolon at the end of most lines, and maybe not at
the end of blocks.
## Multiple return values
Functions cannot directly return multiple values. There’ s a trick, however.
Remember the `()` s we used when showing off complex bindings?
```rust
fn main() {
let (x, y) = (5, 6);
}
```
They form something called a ‘ tuple’ , one of Rust’ s basic types. A tuple is an
anonymous collection of elements. But since a tuple is a singular thing, we can
use it as a way to return multiple values from functions:
```rust
fn main() {
let (x, y) = two_numbers();
println!("The value of x is: {}", x);
println!("The value of y is: {}", y);
}
fn two_numbers() -> (i32, i32) {
(5, 6)
}
```
Running this will show us the values:
```bash
$ cargo run
Compiling functions v0.1.0 (file:///projects/functions)
Running `target/debug/functions`
The value of x is: 5
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.
Let’ s look at the declaration first:
```rust
fn two_numbers() -> (i32, i32) {
(5, 6)
}
```
The `(i32, i32)` should look familiar. We saw it in `let` bindings earlier:
```rust
let (x, y): (i32, i32) = (5, 6);
```
The `(i32, i32)` syntax says “a tuple with two `i32` s in it.” The `(5, 6)`
syntax creates a new one, with `5` and `6` .
This tuple is then returned, and assigned to `x` and `y` :
```rust,ignore
let (x, y) = two_numbers();
```
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.
# Scalar Types
We’ ve seen that every value in Rust has a type of some kind. There are a number
of types which are built into the language itself. First, we’ ll take a look at
‘ scalar’ types, that is, types which represent a single value.
Remember, you can rely on type inference to figure out the type of a binding,
or you can annotate it explicitly:
```rust
fn main() {
let x: i32 = 5;
}
```
## Integers
You’ ve already seen one primitive type: `i32` . There are a number of built-in
number types in Rust.
Here’ s a chart of Rust’ s integer types:
| | signed | unsigned |
|--------|--------|----------|
| 8-bit | i8 | u8 |
| 16-bit | i16 | u16 |
| 32-bit | i32 | u32 |
| 64-bit | i64 | u64 |
| arch | isize | usize |
We have both signed and unsigned variants of numbers, and each variant has an
explicit size. Unsigned numbers are never negative, and signed numbers can be
positive or negative. (Think ‘ plus sign’ or ‘ minus sign’ : that’ s a signed
number.) Signed numbers are stored using ‘ two’ s complement’ representation.
Finally, `isize` and `usize` are different sizes based on the kind of computer
your program is running on. If you are on a 64-bit architecture, they are 64
bits, and if you’ re on a 32-bit one, they’ re 32 bits.
So how do you choose from all these options? Well, if you really don’ t know,
the defaults are a good choice: integer types default to `i32` . The primary use
case for `isize` /`usize` is when indexing some sort of collection. We’ ll talk
more about our first collection, arrays, in just a moment.
## Floating-point numbers
Rust also has two primitive floating-point numbers: `f32` and `f64` . They are
32 bits and 64 bits in size, respectively. The default is `f64` .
```rust
fn main() {
let x = 2.0; // f64
let y: f32 = 3.0; // f32
}
```
Floating-point numbers are represented according to the IEEE-754 standard.
`f32` is a single-precision float, `f64` is double-precision.
## Numeric operations
Rust supports the usual operations you’ d expect on all of these number types:
```rust
fn main() {
// addition
let sum = 5 + 10;
// subtraction
let difference = 95.5 - 4.3;
// multiplication
let product = 4 * 30;
// division
let quotient = 56.7 / 32.2;
// modulus
let remainder = 43 % 5;
}
```
## Booleans
Somewhat fundamental to all computing, Rust has a boolean type, `bool` , with
two possible values:
```rust
fn main() {
let t = true;
let f: bool = false; // with explict type annotation
}
```
The main way to consume boolean values is through conditionals like `if` , which
we’ ll see later in the chapter.
## Characters
We’ ve only worked with numbers so far, but what about letters? Rust’ s most
primitive alphabetic type is the `char` :
```rust
fn main() {
let c = 'z';
let z = 'ℤ ';
}
```
Rust’ s `char` represents a [Unicode Scalar Value], which means that it can
represent a lot more than just ASCII. ‘ Character’ isn’ t really a concept in
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
# Compound Types
Now that we’ ve discussed scalar types, let’ s talk about compound types.
These types can group multiple values of scalar types into another type.
## Tuples
We’ ve seen tuples before, in the guise of binding or returning multiple values
at once. It turns out that there’ s no magic here: tuples are a general way of
making a compound value that groups some number of other values with distinct
types. The number of values grouped is the ‘ arity’ of the tuple.
We create a tuple by writing a comma-separated list of values inside
parentheses; each position in the tuple has a distinct type:
```rust
fn main() {
let tup: (i32, f64, u8) = (500, 6.4, 1);
}
```
Note that, unlike the examples of multiple bindings, here we bound the
single name `tup` to the entire tuple. We can then use pattern
matching to destructure this tuple value:
```rust
fn main() {
let tup: (i32, f64, u8) = (500, 6.4, 1);
let (x, y, z) = tup;
println!("The value of y is: {}", y);
}
```
Tuples are used sparingly in Rust code. This is because the elements of a tuple
are anonymous, which can make code hard to read.
### Tuple indexing
In addition to destructuring through pattern matching, we can also access a
tuple element directly using `.` , followed by the index we want to access:
```rust
fn main() {
let x: (i32, f64, u8) = (500, 6.4, 1);
let five_hundred = x.0;
let six_point_four = x.1;
let one = x.2;
}
```
As you can see, the first index is `0` .
### Single-element tuples
There’ s one last trick with tuples: `(5)` is actually ambiguous: is it a tuple,
or is it a `5` in parethesis? If you need to disambiguate, use a comma:
```rust
fn main() {
let x = (5); // x is an i32, no tuple. Think of it like (5 + 1) without the + 1, they’ re for grouping.
let x = (5,); // x is a (i32), a tuple with one element.
}
```
## Arrays
So far, we’ ve only represented single values in a binding. Sometimes, though,
it’ s useful to have more than one value. These kinds of data structures are
called ‘ collections’ , and arrays are the ones we’ ll learn about first. Arrays
look like this:
```rust
fn main() {
let a = [1, 2, 3, 4, 5];
}
```
An array’ s type consists of the type of the elements it contains, as well as
the length:
```rust
fn main() {
let a: [i32; 5] = [1, 2, 3, 4, 5];
}
```
An array is a single chunk of memory, allocated on the stack.
We can access elements of an array using indexing:
```rust
fn main() {
let a = [1, 2, 3, 4, 5];
let first = a[0];
let second = a[1];
}
```
In this example, `first` will hold the value `1` , and `second` will be bound to
`2` . Note that these values are copied out of the array; if the array changes,
these bindings will not. Here’ s an example, which also shows us how we can
modify elements of the array:
```rust
fn main() {
let mut a = [1, 2, 3, 4, 5];
let first = a[0];
a[0] = 7;
println!("The value of first is: {}", first);
}
```
Running this example will show that `first` is still `1` . If we didn’ t want a
copy, but instead wanted to refer to the first element, whatever its value was,
we need a new concept. We’ ll talk about ‘ references’ in Section 4.
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 there’ s a few other concepts
that we haven’ t covered in full yet. There are two: the `panic!` macro, and a
new way of printing things: `Debug` .
### Panic
We showed what happens when you access elements of an array, but what if we
give an invalid index?
```rust,should_panic
fn main() {
let a = [1, 2, 3, 4, 5];
let invalid = a[10];
println!("The value of invalid is: {}", invalid);
}
```
If we run this example, we will get an error. Let’ s re-use our `functions`
project from before. Change your `src/main.rs` to look like the example, and
run it:
```bash
$ cargo run
Compiling functions v0.1.0 (file:///projects/functions)
Running `target/debug/functions`
thread ‘ < main > ’ panicked at ‘ index out of bounds: the len is 5 but the index is 10’ , src/main.rs:4
Process didn’ t exit successfully: `target/debug/functions` (exit code: 101)
```
It says that our thread panicked, and that our program didn’ t exit
successfully. There’ s also a reason: we had a length of five, but an index of
10.
For now, all you need to know is that a panic will crash your program. Rust’ s
error handling story is described in full in a later chapter.
So why did this code panic? Well, arrays know how many elements they hold. When
we access an element via indexing, Rust will check that the index is less than
the length. If it’ s greater, it will panic, as something is very wrong. This is
our first example of Rust’ s safety principles in action. In many low-level
languages, this kind of check is not done. If you have an incorrect index,
invalid memory can be accessed. Rust protects us against this kind of error.
### Debug
So far, we’ ve been printing values using `{}` . If we try that with an array,
though...
```rust,ignore
fn main() {
let a = [1, 2, 3, 4, 5];
println!("a is: {}", a);
}
```
... we will get an error:
```bash
$ cargo run
Compiling functions v0.1.0 (file:///projects/functions)
src/main.rs:4:25: 4:26 error: the trait `core::fmt::Display` is not implemented for the type `[_; 5]` [E0277]
src/main.rs:4 println!(“a is {}”, a);
^
< std macros > :2:25: 2:56 note: in this expansion of format_args!
< std macros > :3:1: 3:54 note: in this expansion of print! (defined in < std macros > )
src/main.rs:4:5: 4:28 note: in this expansion of println! (defined in < std macros > )
src/main.rs:4:25: 4:26 help: run `rustc --explain E0277` to see a detailed explanation
src/main.rs:4:25: 4:26 note: `[_; 5]` cannot be formatted with the default formatter; try using `:?` instead if you are using a format string
src/main.rs:4:25: 4:26 note: required by `core::fmt::Display::fmt`
error: aborting due to previous error
```
Whew! The core of the error is this part: the trait `core::fmt::Display` is not
implemented. We haven’ t discussed traits yet, so this is bound to be confusing!
Here’ s 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
intended for direct end-user consumption. The primitive types we’ ve seen so far
implement `Display` , as there’ s only one way you’ d show a `1` to a user. But
with arrays, the output is less clear. Do you want commas or not? What about
the `[]` s?
Due to these questions, more complex types in the standard library do not
implement `Display` formatting. There is another kind of formatting, `Debug` ,
which is a bit different: intended for programmer consumption. We can ask
`println!` to use `Debug` formatting with `:?` :
```rust
fn main() {
let a = [1, 2, 3, 4, 5];
println!("a is {:?}", a);
}
```
This will work:
```bash
$ cargo run
Compiling functions v0.1.0 (file:///projects/functions)
Running `target/debug/functions`
a is [1, 2, 3, 4, 5]
```
You’ ll see this repeated later, with other types. And we’ ll cover traits fully
later in the book, Section 9.
# Comments
We strive to make our programs easy to understand, but sometimes, some extra
explanation is warranted. We can leave notes in our source code that the
compiler will ignore. These notes are called ‘ comments’ .
Here’ s a comment:
```rust
// Hello, world.
```
Comments start with two slashes, and last until the end of the line. Larger
comments will need more lines:
```rust
// So we’ re doing something complicated here, long enough that we need
// multiple lines of comments to do it! Whew! Hopefully, this comment will
// explain what’ s going on.
```
Comments can also go at the end of lines:
```rust
fn main() {
let lucky_number = 7; // I’ m feeling lucky today.
}
```
But you’ ll more often see them above:
```rust
fn main() {
// I’ m feeling lucky today.
let lucky_number = 7;
}
```
That’ s all there is to it. Comments are not particularly complicated.
## Documentation comments
However, Rust has another kind of comment: a documentation comment. These
comments don’ t affect the way that the code works, but they do work with Rust’ s
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:
```rust
/// The foo function doesn’ t really do much.
fn foo() {
}
/// We also can use
/// multiple comments here too,
/// like we did before
fn 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 of your documentation comments. For
example, a program with only this:
```rust,ignore
/// What am I documenting?
```
Will give a compiler error:
```text
src/main.rs:1:1: 1:27 error: expected item after doc comment
src/main.rs:1 /// What am I documenting?
^~~~~~~~~~~~~~~~~~~~~~~~~~
```
# Control flow with `if`
> Two roads diverged in a yellow wood,
> And sorry I could not travel both
> And be one traveler, long I stood
> And looked down one as far as I could
> To where it bent in the undergrowth;
>
> - Robert Frost, “The Road Not Taken”
In Rust, there are a few ways to cause our code to branch. The most fundamental
way is by using `if` . An `if` expression gives us two paths forward, and asks
the question, “Which one should I take?”
Let’ s make a new project to explore `if` . Navigate to your projects directory,
and use Cargo to make a new project called `branches` :
```bash
$ cargo new --bin branches
$ cd branches
```
Here’ s a sample program using `if` :
```rust
fn main() {
let condition = true;
if condition {
println!("condition was true");
} else {
println!("condition was false");
}
}
```
Let's try running it:
```bash
$ cargo run
Compiling branches v0.1.0 (file:///projects/branches)
Running `target/debug/branches`
condition was true
```
We can change the value of `condition` :
```rust
let condition = false;
```
And then run it again:
```bash
$ cargo run
Compiling branches v0.1.0 (file:///projects/branches)
Running `target/debug/branches`
condition was false
```
This is the very basic structure of `if` : _if_ the condition is true, then
execute some code. If it’ s not true, then execute some other code, after
`else` .
An `else` is not required:
```rust
fn main() {
let condition = false;
if condition {
println!("condition was true");
}
}
```
In this case, nothing is printed.
It’ s also worth noting that `condition` here _must_ be a `bool` . Let’ s try an
example with something else:
```rust,ignore
fn main() {
let condition = 5;
if condition {
println!("condition was five");
}
}
```
If we try to run this program, Rust will complain:
```bash
Compiling branches v0.1.0 (file:///projects/branches)
src/main.rs:4:8: 4:17 error: mismatched types:
expected `bool` ,
found `_`
(expected bool,
found integral variable) [E0308]
src/main.rs:4 if condition {
^~~~~~~~~
src/main.rs:4:8: 4:17 help: run `rustc --explain E0308` to see a detailed explanation
error: aborting due to previous error
Could not compile `branches` .
```
We expected a `bool` , but got an integer. Rust will not automatically try to convert non-boolean types to a boolean here. We must be explicit.
## `else if`
We can make multiple decisions by combining `if` and `else` in another way:
```rust
fn main() {
let number = 5;
if number == 3 {
println!("condition was 3");
} else if number == 4 {
println!("condition was 4");
} else if number == 5 {
println!("condition was 5");
} else {
println!("condition was something else");
}
}
```
Let's try running it:
```bash
$ cargo run
Compiling branches v0.1.0 (file:///projects/branches)
Running `target/debug/branches`
condition was 5
```
When this program executes, it will check each `if` in turn, and execute the
first body for which the condition holds true.
Using a single `else if` can be okay, but if you find yourself with more than one,
you may want to refactor your code. Rust has a more powerful branching construct
called `match` for these cases. We'll cover it later, when we talk about `enums` .
## `if` as an expression
There’ s one last detail we need to learn about `if` : it’ s an expression. That means
that we can use it on the right hand side of a `let` binding, for instance:
```rust
fn main() {
let condition = true;
let number = if condition {
5
} else {
6
};
println!("The value of number is: {}", number);
}
```
Let’ s run this:
```bash
$ cargo run
Compiling branches v0.1.0 (file:///projects/branches)
Running `target/debug/branches`
The value of number is: 5
```
Remember, blocks of code evaluate to the last expression in them. And numbers
by themselves are also expressions. So in this case, the value of the whole
`if` expression depends on which block of code executes.
There’ s another small detail involved here: this means that if you use `if`
in this way, both arms of the `if` must be the same type. This doesn’ t work:
```rust,ignore
fn main() {
let condition = true;
let number = if condition {
5
} else {
"six"
};
println!("The value of number is: {}", number);
}
```
If we try to run this, we’ ll get an error:
```bash
Compiling branches v0.1.0 (file:///projects/branches)
src/main.rs:4:18: 8:6 error: if and else have incompatible types:
expected `_` ,
found `&‘ static str`
(expected integral variable,
found & -ptr) [E0308]
src/main.rs:4 let number = if condition {
src/main.rs:5 5
src/main.rs:6 } else {
src/main.rs:7 "six"
src/main.rs:8 };
src/main.rs:4:18: 8:6 help: run `rustc --explain E0308` to see a detailed explanation
error: aborting due to previous error
Could not compile `branches` .
```
`if` and `else` have incompatible types. This can’ t work.
# Loops
It’ s often quite useful to be able to execute a block of code more than one
time. For this, we have several constructs, called ‘ loops’ .
To try out loops, let’ s make a new project. Navigate to your projects folder
and use Cargo to make a new one:
```bash
$ cargo new --bin loops
$ cd loops
```
There are three kinds of loops in Rust: `loop` , `while` , and `for` . Let’ s dig
in.
## `loop`
The `loop` keyword is very straightforward: it executes a block of code over
and over and over and over and over and over forever. Change your `src/main.rs`
file to look like this:
```rust,ignore
fn main() {
loop {
println!("again!");
}
}
```
If we run this program, we’ ll see ‘ `again!`’ printed over and over again. So
how does our program end? It doesn’ t, until we kill it. Most terminals support
a keyboard shortcut, ‘ control-c’ , to stop a runaway program. Give it a try:
```bash
$ cargo run
Compiling loops v0.1.0 (file:///projects/loops)
Running `target/debug/loops`
again!
again!
again!
again!
^Cagain!
```
That `^C` there is where I hit control-c.
That’ s a lot of trouble though! Luckily, there’ s a way to break an infinite `loop` .
### Breaking out of a loop
The `break` keyword will allow us to quit looping. Try this version out:
```rust
fn main() {
loop {
println!("once!");
break;
}
}
```
If you run this program with `cargo run` , you’ ll see that it only executes one
time:
```bash
$ cargo run
Compiling loops v0.1.0 (file:///projects/loops)
Running `target/debug/loops`
once!
```
When a Rust program hits a `break` statement, it will exit the current loop.
## `while`
What if we took `loop` , `break` , and `if` , and put them together? Something
like this:
```rust
fn main() {
let mut number = 3;
loop {
if number != 0 {
println!("{}!", number);
number = number - 1;
} else {
break;
}
}
println!("LIFTOFF!!!");
}
```
If we run this, we’ ll get some output:
```bash
Compiling loops v0.1.0 (file:///projects/loops)
Running `target/debug/loops`
3!
2!
1!
LIFTOFF!!!
```
The core of this example is in the combination of these three constructs:
```rust,ignore
loop {
if number != 0 {
// do stuff
} else {
break;
}
```
We want to `loop` , but only while some sort of condition is true. As soon as it
isn't, we want to `break` out of the loop.
This pattern is so common that we have a language construct for it: `while` .
Here's the same example, but using `while` instead:
```rust
fn main() {
let mut number = 3;
while number != 0 {
println!("{}!", number);
number = number - 1;
}
println!("LIFTOFF!!!");
}
```
This lets us get rid of a lot of nesting, and is more clear: while a condition holds,
run this code.
## `for`
We can use this `while` construct to loop over the elements of a collection, like an
array:
```rust
fn main() {
let a = [1, 2, 3, 4, 5];
let mut index = 0;
while index < 5 {
println!("the value is is: {}", a[index]);
index = index + 1;
}
}
```
Running this will print out every element of the array:
```bash
$ cargo run
Compiling loops v0.1.0 (file:///projects/loops)
Running `target/debug/loops`
the value is: 1
the value is: 2
the value is: 3
the value is: 4
the value is: 5
```
Here, we're counting up instead of down: we start at zero, then loop until we
hit the final index of our array.
This approach is error-prone, though. If we get the index length incorrect, we
will end up causing a `panic!` . This is also slow, as the compiler needs to do
that check on every element on every iteration through the loop.
Instead, we can use our last kind of loop: the `for` loop. It looks like this:
```rust
fn main() {
let a = [1, 2, 3, 4, 5];
let mut index = 0;
for element in a.iter() {
println!("the value is: {}", element);
}
}
```
** NOTE: see [https://github.com/rust-lang/rust/issues/25725#issuecomment-166365658 ](https://github.com/rust-lang/rust/issues/25725#issuecomment-166365658 ), we may want to change this **
If we run this, we'll see the same output as the previous example.
** I'm going to leave it at this for now until we decide how we want to do it**