Backport changes to Variable Bindings in Detail section

This commit is contained in:
Carol (Nichols || Goulding) 2016-07-03 14:51:52 -04:00
parent e094c3bd4e
commit 8bf85b6a58
3 changed files with 573 additions and 639 deletions

View File

@ -9,7 +9,7 @@
- [Up and Running](ch03-01-up-and-running.md)
- [Anatomy of a Rust Program](ch03-02-anatomy-of-a-rust-program.md)
- [Variable Bindings](ch03-02-variable-bindings.md)
- [Variable Bindings in Detail](ch03-03-variable-bindings-in-detail.md)
- [Functions](ch03-03-functions.md)
- [Scalar Types](ch03-04-scalar-types.md)
- [Compound Types](ch03-05-compound-types.md)

View File

@ -1,638 +0,0 @@
# Variable Bindings
The foundation of virtually every program is the ability to store and modify
data. Rust programs are no different. Lets start with a short example.
## The basics of bindings
First, well generate a new project with Cargo. Open a terminal, and navigate
to the directory where youd like to keep your projects. From there, lets
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!");
}
```
Lets 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. Lets break this down, line by line.
```rust,ignore
fn main() {
```
The `main()` function is the entry point of every Rust program. 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. The opening curly brace, `{`, indicates the
start of the functions 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, well see more complex
and powerful patterns as we go along.
Before we do that, though, lets finish investigating this example. Heres the
next line:
```rust,ignore
println!("The value of x is: {}", x);
```
The `println!` macro prints text to the screen. We can tell that its a macro
due to the `!`. We wont learn how to write macros until much later in the
book, but well 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. Heres 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 well 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
Lets 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
```
Weve created two bindings with one `let`! Heres our pattern:
```text
(x, y)
```
And heres 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, well
figure out which style is better, but its mostly a judgement call.
## Type annotations
You may have noticed that we didnt 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.
Lets 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. Well talk more about Rusts basic types in section 3.3.
Heres 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. Heres 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, heres 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
```
Its all good. This raises a question, though: what if we try to print out a
binding before we declare a value? Heres 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 wont 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
Theres 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. Heres `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 youre stuck on an error. The compiler is
your friend, and is here to help.
## Mutable bindings
What about changing the value of a binding? Heres 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`. Thats right: bindings
are immutable. But theyre only immutable by default. In a pattern, when were
creating a new name, we can add `mut` in front to make the binding a mutable
one. Heres 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; its 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);
^
```
Its 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 havent 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. Its 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. Well talk about that in the next
section, when we discuss functions.
## Scope
Variable bindings have a scope in which theyre 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.
Heres 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, wed 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!("Lets 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. Heres 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 didnt 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 youd
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. Lets
assume that after we calculate `12`, we dont want to modify `x` again. If we
had written this program in a mutable style, like this:
```rust
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 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. Its this part:
```text
src/main.rs:2:9: 2:10 warning: unused variable: `x`, #[warn(unused_variables)] on by default
```
Heres 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 isnt _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 well
discuss in a later section. 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. 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.
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. Heres 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
```

View File

@ -0,0 +1,572 @@
## Variable Bindings in Detail
So far, weve created the simplest kind of variable binding, but the `let`
statement has some more tricks up its sleeve. Now we'll look at doing more
complex things: creating multiple bindings at once, adding type annotations,
creating mutating bindings, understanding shadowing, and more.
### Creating Multiple Bindings
The previous example program just bound one variable, but it's also possible to
create multiple variable bindings in one go. Lets try a more complex example,
creating two variable bindings at once. Change your example program to this:
<!-- Oh yeah, this is a much better place to have this example rather than the
one I suggested above /Carol -->
```rust
fn main() {
let (x, y) = (5, 6);
println!("The value of x is: {}", x);
println!("The value of y is: {}", y);
}
```
And enter `cargo run` to run it:
```bash
$ 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
```
Weve created two bindings with one `let` statement! The `let` statement binds
the values in `(5, 6)` to the corresponding patterns of `(x, y)`. The first
value `5` binds to the first part of the pattern, `x`, and the second value `6`
binds to `y`. We could alternatively have used two `let` statements to the same
effect, as follows:
```rust
fn main() {
let x = 5;
let y = 6;
}
```
In simple cases like this, where we are only binding two variables, two `let`
statements may be clearer in the code, but when you're creating many multiple
bindings, it's useful to be able to do so all at once. Deciding which technique
to use is mostly a judgement call, and as you become more proficient in Rust,
youll be able to figure out which style is better in each case.
### Delayed Initialization
The examples so far have all provided bindings with an initial value, but that
isn't always necessary. Rather, we can assign a value for the binding later,
after the `let` statement. To try this out, write the following program:
```rust
fn main() {
let x;
x = 5;
println!("The value of x is: {}", x);
}
```
And enter `cargo run` to run it:
```bash
$ cargo run
Compiling bindings v0.1.0 (file:///projects/bindings)
Running `target/debug/bindings`
The value of x is: 5
```
As you can see, this works just like the previous program, in which we assigned
an initial value.
This raises an interesting question: what happens if we try to print out a
binding before we declare a value? Let's find out. Modify your code to look
like the following:
```rust,ignore
fn main() {
let x;
println!("The value of x is: {}", x);
x = 5;
}
```
When you enter `cargo run` to run this code, you should see output like this
after the command:
```bash
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.
```
There's been an error! The compiler wont let us write a program like this, and
instead it requests that you assign a value to the variable `x`. 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 will 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
responds with an error to prod the programmer to declare the value they want.
We must initialize any variable before we can use it.
PROD: START BOX
######Extended Error Explanations
Now that you've seen an example of a Rust error, I want to point out one
particularly useful aspect of errors. Rust encourages you to seek further
information on the kind of error you've received with output like this:
```bash
src/main.rs:4:39: 4:40 help: run `rustc --explain E0381` to see a detailed explanation
```
This tells us that if we pass the `--explain` flag to `rustc` with the provided
error code, we can see an extended explanation, which will try to explain
common causes of and solutions to that kind of error. Not every error has a
longer explanation, but many do. Heres the explanation for the `E0381` error
we received previously:
```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 youre stuck on an error, so don't
hesitate to look up the error code. The compiler is your friend, and it's there
to help.
PROD: END BOX
### Mutable bindings
By default, variable bindings are *immutable*, meaning that once a value is
bound, you can't change that value. Try writing the following sample program to
illustrate this:
```rust,ignore
fn main() {
let x = 5;
x = 6;
println!("The value of x is: {}", x);
}
```
Save and run the program, and you should receive another error message, as in
this output:
```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 includes the message `re-assigment of immutable variable` because the
program tried to assign a second value to the `x` variable. But bindings are
immutable only by default; you can make them mutable by adding `mut` in front
of the variable name. For example, change the program you just wrote to the
following:
```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
```
Using `mut`, we change the value that `x` binds to from `5` to `6`. Note,
however, that `mut` is part of the pattern in the `let` statement. This becomes
more obvious if we try to add mutability to a pattern that binds multiple
variables in the same way as we did for a single variable, like this:
<!--- Steve: regarding our previous note on avoiding negative examples -- if we
do want to show a negative example, we ought to make it clear that that's
what's going to happen, so the reader doesn't go through expecting their code
to work and then gets a faceful of error. I've edited above slightly with this
in mind /Liz -->
```rust,ignore
fn main() {
let (mut x, y) = (5, 6);
x = 7;
y = 8;
}
```
If you run this code, the compiler will output an error:
```bash
$ cargo run
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);
^
```
The way `mut` is used here, the compiler is fine with reassigning the `x`
variable, but not the `y` variable. That's because `mut` only applies to the
name that directly follows it, not the whole pattern. For the compiler to allow
you to reassign the `y` variable, you'd need to write the pattern as `(mut x,
mut y)` instead.
<!-- If I change the example to have `(mut x, mut y)`, it compiles but gives me
warnings about unused variables and assignments. Do we care about that? Could
be easily solved by throwing in some println!s as in previous examples. /Carol
-->
One thing to know about mutating bindings: `mut` allows you to mutate _the
binding_, but not _what the name binds to_. In other words, the value is not
what changes, but rather the path between the value and the name. For example:
```rust
fn main() {
let mut x = 5;
x = 6;
}
```
This does not change the value that `x` is bound to, but creates a new value
(`6`) and changes the binding so that it binds the name `x` to this new value
instead. This subtle but important difference will become more important as
your Rust programs get more complex.
<!--
I feel like this example doesn't make the concept of "mutating the binding, not
the value" clear to me... what about this instead?
```rust
fn main() {
let mut x = 5;
let y = x;
x = x + 1;
println!("The value of x is {}. The value of y is {}.", x, y);
}
```
which prints out "The value of x is 6. The value of y is 5.". The 5 is still
around in y, where in the previous example I don't really have a way to *see*
that. This example also has some subtlety around value vs reference that I'm
not sure *I* understand precisely correctly, so perhaps this isn't really a
good example of "mutating the binding, not the value" ;)
I do feel like either this example could be more illustrative or this whole
aside should be taken out to be addressed later, though.
/Carol
-->
### Variable Binding Scope
Another important thing to know about variable bindings is that they are only
valid as long as they are *in scope*. That scope begins at the point where the
binding is declared, and ends with the curly brace that closes the block of
code containing that binding. We cannot access bindings "before they come into
scope" or "after they go out of scope." Heres an example to illustrate this:
<!-- I feel like these examples don't really illustrate anything since the
println!s don't *use* x or y. They're basically comments. What do you think
about encouraging the reader to modify the println!s in order to use x and y,
to see when the compiler errors or not?
For example, the first println! in the next example that says `println!("x is
not yet in scope");` could instead say `println!("x is not yet in scope. Try to
print x in this statement to see the compiler error!");`. When x is in scope,
the println!s could use it.
/Carol -->
```rust
fn main() {
println!("x is not yet in scope");
let x = 5;
println!("x is now in scope");
println!("In real code, wed now do a bunch of work.");
println!("x will go out of scope now! The next curly brace is ending the main function.");
}
```
The variable binding for `x` goes out of scope with the last curly brace in the
`main()` function.
This example only has one scope, though. In Rust, it's possible to create
arbitrary scopes within a scope by placing code within another pair of curly
braces (we'll look at this more in the next chapter). For example:
```rust
fn main() {
println!("x is not yet in scope");
let x = 5;
println!("x is now in scope");
println!("Lets 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.");
}
```
The `y` variable is only in scope in the section of the code that's between the
nested pair of curly braces, whereas `x` is in scope from the `let` statement
that binds it until the final curly brace. The scope of bindings will become
much more important later as you learn about references in Chapter XX.
### Shadowing Earlier Bindings
<!--- TR: Can you help add a definition of shadowing, to let the reader know
what to look out for here? The shadowed value takes precedance over the
original value? /Liz -->
<!-- I wanted to make sure I got this correct, so I
did some research-- the wikipedia page on variable shadowing
(https://en.wikipedia.org/wiki/Variable_shadowing) says "This outer variable is
said to be shadowed by the inner variable, while the inner identifier is said
to mask the outer identifier." so I reworded the sentence needing the
definition since it was backwards. /Carol -->
One final thing about bindings: they can *shadow* previous bindings with the
same name. Shadowing is what happens when you declare two bindings with the
same name. We say that the first binding is shadowed by the second, which
means that the second binding's value is what you will see when you use the
variable after the second binding. This can be useful if youd like to perform
a few transformations on a value, but still leave the binding 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 program first binds `x` to a value of `5`. Then, it shadows `x`, taking
the original value and adding `1` so that the value of `x` is then `6`. The
third `let` statement shadows `x` again, taking the previous value and
multiplying it by `2` to give `x` a final value of `12`. If you run this, it
will output:
```bash
$ cargo run
Compiling bindings v0.1.0 (file:///projects/bindings)
Running `target/debug/bindings`
The value of x is: 12
```
Shadowing is useful because it lets us modify `x` without having to make the
variable mutable. This means the compiler will still warn us if we accidentally
try to mutate `x` directly later. For example, say after calculating `12` we
dont want `x` to be modified again; if we write the program in a mutable
style, like this:
```rust
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 `x` again, to `15`. A similar program using the
default immutable style, however, will let us know about that accidental
mutation. Here's an example:
```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 this, we get an error:
```bash
$ cargo run
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`.
```
Since we don't want the binding to be mutable, this exactly what should happen.
#### Shadowing Over Bindings
You can also shadow bindings over one another, without re-using the initial
binding in the value. Here's how that looks:
```rust
fn main() {
let x = 5;
let x = 6;
println!("The value of x is: {}", x);
}
```
Running this sample program, we can see the shadowing in action:
```bash
$ cargo run
Compiling bindings v0.1.0 (file:///projects/bindings)
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
```
Rust gives the value of `x` as `6`, which is the value from the *second* `let`
statement. There are a few interesting things in this output. First, that Rust
will compile and run the program without issue. This is because we haven't
mutated the value; instead, we declared a _new_ binding that is _also_ named
`x`, and gave it a new value.
The other interesting thing in this output is this error line:
```bash
src/main.rs:2:9: 2:10 warning: unused variable: `x`, #[warn(unused_variables)] on by default
```
Rust is pointing out that we shadowed `x`, but never used the initial value.
Doing so isnt _wrong_, but Rust is checking whether this is intentional and
not just a mistake. In this case, the compiler issues a warning, but still
compiles our program. A warning like this is called a *lint*, which is an old
term for the bits of fluff and fibers in sheeps 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 (the
statement `let x = 5`) that we dont need. Even though our program works just
fine, listening to these warnings and fixing the problems they point out is
worthwhile, as they can be signs of a larger problem. In this case, we may not
have realized that we were shadowing `x`, when we meant to, say, define a new
variable with a different name.
Shadowing can take some time to get used to, but its very powerful and works
well with immutability.
#### Shadowing and Scopes
Like any binding, a binding that shadows another binding becomes invalid at the
end of a scope. Heres an example program to illustrate this:
```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);
}
```
This code first creates the `x` variable and prints `x` to the terminal. Then,
inside a new scope, it creates a new binding for `x` with a new value, and
prints that value. When the arbitrary scope ends, `x` is printed once more. If
we run this example, we can see the shadow appear and disappear in the output:
```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
```
In this case, the binding value reverts to the original value once the shadow
binding goes out of scope.