2015-01-16 14:30:27 -06:00
|
|
|
|
% Variable Bindings
|
2014-12-02 08:20:48 -06:00
|
|
|
|
|
2015-04-25 10:52:03 -05:00
|
|
|
|
Virtually every non-'Hello World’ Rust program uses *variable bindings*. They
|
2015-09-29 19:42:52 -05:00
|
|
|
|
bind some value to a name, so it can be used later. `let` is
|
2016-01-07 13:05:00 -06:00
|
|
|
|
used to introduce a binding, like this:
|
2014-12-02 08:20:48 -06:00
|
|
|
|
|
2015-04-09 15:30:43 -05:00
|
|
|
|
```rust
|
2014-12-02 08:20:48 -06:00
|
|
|
|
fn main() {
|
|
|
|
|
let x = 5;
|
|
|
|
|
}
|
|
|
|
|
```
|
|
|
|
|
|
2015-04-09 15:30:43 -05:00
|
|
|
|
Putting `fn main() {` in each example is a bit tedious, so we’ll leave that out
|
|
|
|
|
in the future. If you’re following along, make sure to edit your `main()`
|
|
|
|
|
function, rather than leaving it off. Otherwise, you’ll get an error.
|
2014-12-02 08:20:48 -06:00
|
|
|
|
|
2015-09-29 19:42:52 -05:00
|
|
|
|
# Patterns
|
|
|
|
|
|
|
|
|
|
In many languages, a variable binding would be called a *variable*, but Rust’s
|
|
|
|
|
variable bindings have a few tricks up their sleeves. For example the
|
2016-01-07 13:05:00 -06:00
|
|
|
|
left-hand side of a `let` expression is a ‘[pattern][pattern]’, not a
|
2015-09-29 19:42:52 -05:00
|
|
|
|
variable name. This means we can do things like:
|
2014-12-02 08:20:48 -06:00
|
|
|
|
|
2015-04-09 15:30:43 -05:00
|
|
|
|
```rust
|
2014-12-02 08:20:48 -06:00
|
|
|
|
let (x, y) = (1, 2);
|
|
|
|
|
```
|
|
|
|
|
|
|
|
|
|
After this expression is evaluated, `x` will be one, and `y` will be two.
|
2015-04-09 15:30:43 -05:00
|
|
|
|
Patterns are really powerful, and have [their own section][pattern] in the
|
2016-01-07 13:05:00 -06:00
|
|
|
|
book. We don’t need those features for now, so we’ll keep this in the back
|
2015-04-09 15:30:43 -05:00
|
|
|
|
of our minds as we go forward.
|
|
|
|
|
|
|
|
|
|
[pattern]: patterns.html
|
2014-12-02 08:20:48 -06:00
|
|
|
|
|
2015-09-29 19:42:52 -05:00
|
|
|
|
# Type annotations
|
|
|
|
|
|
2014-12-02 08:20:48 -06:00
|
|
|
|
Rust is a statically typed language, which means that we specify our types up
|
2015-04-09 15:30:43 -05:00
|
|
|
|
front, and they’re checked at compile time. So why does our first example
|
|
|
|
|
compile? Well, Rust has this thing called ‘type inference’. If it can figure
|
|
|
|
|
out what the type of something is, Rust doesn’t require you to actually type it
|
|
|
|
|
out.
|
2014-12-02 08:20:48 -06:00
|
|
|
|
|
|
|
|
|
We can add the type if we want to, though. Types come after a colon (`:`):
|
|
|
|
|
|
2015-04-09 15:30:43 -05:00
|
|
|
|
```rust
|
2014-12-02 08:20:48 -06:00
|
|
|
|
let x: i32 = 5;
|
|
|
|
|
```
|
|
|
|
|
|
2015-04-09 15:30:43 -05:00
|
|
|
|
If I asked you to read this out loud to the rest of the class, you’d say “`x`
|
|
|
|
|
is a binding with the type `i32` and the value `five`.”
|
2014-12-02 08:20:48 -06:00
|
|
|
|
|
2015-02-15 12:51:36 -06:00
|
|
|
|
In this case we chose to represent `x` as a 32-bit signed integer. Rust has
|
|
|
|
|
many different primitive integer types. They begin with `i` for signed integers
|
|
|
|
|
and `u` for unsigned integers. The possible integer sizes are 8, 16, 32, and 64
|
|
|
|
|
bits.
|
|
|
|
|
|
2014-12-02 08:20:48 -06:00
|
|
|
|
In future examples, we may annotate the type in a comment. The examples will
|
|
|
|
|
look like this:
|
|
|
|
|
|
2015-04-09 15:30:43 -05:00
|
|
|
|
```rust
|
2014-12-02 08:20:48 -06:00
|
|
|
|
fn main() {
|
|
|
|
|
let x = 5; // x: i32
|
|
|
|
|
}
|
|
|
|
|
```
|
|
|
|
|
|
2015-04-09 15:30:43 -05:00
|
|
|
|
Note the similarities between this annotation and the syntax you use with
|
|
|
|
|
`let`. Including these kinds of comments is not idiomatic Rust, but we'll
|
|
|
|
|
occasionally include them to help you understand what the types that Rust
|
|
|
|
|
infers are.
|
2014-12-02 08:20:48 -06:00
|
|
|
|
|
2015-09-29 19:42:52 -05:00
|
|
|
|
# Mutability
|
|
|
|
|
|
2015-01-08 18:52:50 -06:00
|
|
|
|
By default, bindings are *immutable*. This code will not compile:
|
2014-12-02 08:20:48 -06:00
|
|
|
|
|
2015-04-09 15:30:43 -05:00
|
|
|
|
```rust,ignore
|
2014-12-02 08:20:48 -06:00
|
|
|
|
let x = 5;
|
|
|
|
|
x = 10;
|
|
|
|
|
```
|
|
|
|
|
|
|
|
|
|
It will give you this error:
|
|
|
|
|
|
|
|
|
|
```text
|
|
|
|
|
error: re-assignment of immutable variable `x`
|
|
|
|
|
x = 10;
|
|
|
|
|
^~~~~~~
|
|
|
|
|
```
|
|
|
|
|
|
|
|
|
|
If you want a binding to be mutable, you can use `mut`:
|
|
|
|
|
|
2015-04-09 15:30:43 -05:00
|
|
|
|
```rust
|
2014-12-02 08:20:48 -06:00
|
|
|
|
let mut x = 5; // mut x: i32
|
|
|
|
|
x = 10;
|
|
|
|
|
```
|
|
|
|
|
|
|
|
|
|
There is no single reason that bindings are immutable by default, but we can
|
2015-04-09 15:30:43 -05:00
|
|
|
|
think about it through one of Rust’s primary focuses: safety. If you forget to
|
2014-12-02 08:20:48 -06:00
|
|
|
|
say `mut`, the compiler will catch it, and let you know that you have mutated
|
|
|
|
|
something you may not have intended to mutate. If bindings were mutable by
|
|
|
|
|
default, the compiler would not be able to tell you this. If you _did_ intend
|
|
|
|
|
mutation, then the solution is quite easy: add `mut`.
|
|
|
|
|
|
2015-04-09 15:30:43 -05:00
|
|
|
|
There are other good reasons to avoid mutable state when possible, but they’re
|
2014-12-02 08:20:48 -06:00
|
|
|
|
out of the scope of this guide. In general, you can often avoid explicit
|
|
|
|
|
mutation, and so it is preferable in Rust. That said, sometimes, mutation is
|
2015-04-09 15:30:43 -05:00
|
|
|
|
what you need, so it’s not verboten.
|
2014-12-02 08:20:48 -06:00
|
|
|
|
|
2015-09-29 19:42:52 -05:00
|
|
|
|
# Initializing bindings
|
|
|
|
|
|
|
|
|
|
Rust variable bindings have one more aspect that differs from other languages:
|
|
|
|
|
bindings are required to be initialized with a value before you're allowed to
|
|
|
|
|
use them.
|
2014-12-02 08:20:48 -06:00
|
|
|
|
|
2015-04-09 15:30:43 -05:00
|
|
|
|
Let’s try it out. Change your `src/main.rs` file to look like this:
|
2014-12-02 08:20:48 -06:00
|
|
|
|
|
2015-04-09 15:30:43 -05:00
|
|
|
|
```rust
|
2014-12-02 08:20:48 -06:00
|
|
|
|
fn main() {
|
|
|
|
|
let x: i32;
|
|
|
|
|
|
|
|
|
|
println!("Hello world!");
|
|
|
|
|
}
|
|
|
|
|
```
|
|
|
|
|
|
2015-04-09 15:30:43 -05:00
|
|
|
|
You can use `cargo build` on the command line to build it. You’ll get a
|
|
|
|
|
warning, but it will still print "Hello, world!":
|
2014-12-02 08:20:48 -06:00
|
|
|
|
|
|
|
|
|
```text
|
|
|
|
|
Compiling hello_world v0.0.1 (file:///home/you/projects/hello_world)
|
2015-04-09 15:30:43 -05:00
|
|
|
|
src/main.rs:2:9: 2:10 warning: unused variable: `x`, #[warn(unused_variable)]
|
|
|
|
|
on by default
|
2014-12-02 08:20:48 -06:00
|
|
|
|
src/main.rs:2 let x: i32;
|
|
|
|
|
^
|
|
|
|
|
```
|
|
|
|
|
|
2015-04-09 15:30:43 -05:00
|
|
|
|
Rust warns us that we never use the variable binding, but since we never use
|
|
|
|
|
it, no harm, no foul. Things change if we try to actually use this `x`,
|
|
|
|
|
however. Let’s do that. Change your program to look like this:
|
2014-12-02 08:20:48 -06:00
|
|
|
|
|
2015-04-09 15:30:43 -05:00
|
|
|
|
```rust,ignore
|
2014-12-02 08:20:48 -06:00
|
|
|
|
fn main() {
|
|
|
|
|
let x: i32;
|
|
|
|
|
|
|
|
|
|
println!("The value of x is: {}", x);
|
|
|
|
|
}
|
|
|
|
|
```
|
|
|
|
|
|
2015-04-09 15:30:43 -05:00
|
|
|
|
And try to build it. You’ll get an error:
|
2014-12-02 08:20:48 -06:00
|
|
|
|
|
2015-04-09 15:30:43 -05:00
|
|
|
|
```bash
|
2014-12-02 08:20:48 -06:00
|
|
|
|
$ cargo build
|
|
|
|
|
Compiling hello_world v0.0.1 (file:///home/you/projects/hello_world)
|
|
|
|
|
src/main.rs:4:39: 4:40 error: use of possibly uninitialized variable: `x`
|
|
|
|
|
src/main.rs:4 println!("The value of x is: {}", x);
|
|
|
|
|
^
|
|
|
|
|
note: in expansion of format_args!
|
|
|
|
|
<std macros>:2:23: 2:77 note: expansion site
|
|
|
|
|
<std macros>:1:1: 3:2 note: in expansion of println!
|
|
|
|
|
src/main.rs:4:5: 4:42 note: expansion site
|
|
|
|
|
error: aborting due to previous error
|
|
|
|
|
Could not compile `hello_world`.
|
|
|
|
|
```
|
|
|
|
|
|
2015-04-09 15:30:43 -05:00
|
|
|
|
Rust will not let us use a value that has not been initialized. Next, let’s
|
2014-12-02 08:20:48 -06:00
|
|
|
|
talk about this stuff we've added to `println!`.
|
|
|
|
|
|
|
|
|
|
If you include two curly braces (`{}`, some call them moustaches...) in your
|
|
|
|
|
string to print, Rust will interpret this as a request to interpolate some sort
|
2015-01-08 18:52:50 -06:00
|
|
|
|
of value. *String interpolation* is a computer science term that means "stick
|
2014-12-02 08:20:48 -06:00
|
|
|
|
in the middle of a string." We add a comma, and then `x`, to indicate that we
|
2015-04-09 15:30:43 -05:00
|
|
|
|
want `x` to be the value we’re interpolating. The comma is used to separate
|
|
|
|
|
arguments we pass to functions and macros, if you’re passing more than one.
|
|
|
|
|
|
2016-01-07 13:05:00 -06:00
|
|
|
|
When you use the curly braces, Rust will attempt to display the value in a
|
2015-04-09 15:30:43 -05:00
|
|
|
|
meaningful way by checking out its type. If you want to specify the format in a
|
|
|
|
|
more detailed manner, there are a [wide number of options available][format].
|
2016-01-07 13:05:00 -06:00
|
|
|
|
For now, we'll stick to the default: integers aren't very complicated to
|
2015-04-09 15:30:43 -05:00
|
|
|
|
print.
|
|
|
|
|
|
|
|
|
|
[format]: ../std/fmt/index.html
|
2015-09-29 19:42:52 -05:00
|
|
|
|
|
|
|
|
|
# Scope and shadowing
|
|
|
|
|
|
|
|
|
|
Let’s get back to bindings. Variable bindings have a scope - they are
|
|
|
|
|
constrained to live in a block they were defined in. A block is a collection
|
|
|
|
|
of statements enclosed by `{` and `}`. Function definitions are also blocks!
|
|
|
|
|
In the following example we define two variable bindings, `x` and `y`, which
|
|
|
|
|
live in different blocks. `x` can be accessed from inside the `fn main() {}`
|
|
|
|
|
block, while `y` can be accessed only from inside the inner block:
|
|
|
|
|
|
|
|
|
|
```rust,ignore
|
|
|
|
|
fn main() {
|
|
|
|
|
let x: i32 = 17;
|
|
|
|
|
{
|
|
|
|
|
let y: i32 = 3;
|
|
|
|
|
println!("The value of x is {} and value of y is {}", x, y);
|
|
|
|
|
}
|
|
|
|
|
println!("The value of x is {} and value of y is {}", x, y); // This won't work
|
|
|
|
|
}
|
|
|
|
|
```
|
|
|
|
|
|
|
|
|
|
The first `println!` would print "The value of x is 17 and the value of y is
|
|
|
|
|
3", but this example cannot be compiled successfully, because the second
|
|
|
|
|
`println!` cannot access the value of `y`, since it is not in scope anymore.
|
|
|
|
|
Instead we get this error:
|
|
|
|
|
|
|
|
|
|
```bash
|
|
|
|
|
$ cargo build
|
|
|
|
|
Compiling hello v0.1.0 (file:///home/you/projects/hello_world)
|
|
|
|
|
main.rs:7:62: 7:63 error: unresolved name `y`. Did you mean `x`? [E0425]
|
|
|
|
|
main.rs:7 println!("The value of x is {} and value of y is {}", x, y); // This won't work
|
|
|
|
|
^
|
|
|
|
|
note: in expansion of format_args!
|
|
|
|
|
<std macros>:2:25: 2:56 note: expansion site
|
|
|
|
|
<std macros>:1:1: 2:62 note: in expansion of print!
|
|
|
|
|
<std macros>:3:1: 3:54 note: expansion site
|
|
|
|
|
<std macros>:1:1: 3:58 note: in expansion of println!
|
|
|
|
|
main.rs:7:5: 7:65 note: expansion site
|
|
|
|
|
main.rs:7:62: 7:63 help: run `rustc --explain E0425` to see a detailed explanation
|
|
|
|
|
error: aborting due to previous error
|
|
|
|
|
Could not compile `hello`.
|
|
|
|
|
|
|
|
|
|
To learn more, run the command again with --verbose.
|
|
|
|
|
```
|
|
|
|
|
|
2015-10-13 08:44:11 -05:00
|
|
|
|
Additionally, variable bindings can be shadowed. This means that a later
|
2015-09-29 19:42:52 -05:00
|
|
|
|
variable binding with the same name as another binding, that's currently in
|
|
|
|
|
scope, will override the previous binding.
|
|
|
|
|
|
|
|
|
|
```rust
|
|
|
|
|
let x: i32 = 8;
|
|
|
|
|
{
|
|
|
|
|
println!("{}", x); // Prints "8"
|
|
|
|
|
let x = 12;
|
|
|
|
|
println!("{}", x); // Prints "12"
|
|
|
|
|
}
|
|
|
|
|
println!("{}", x); // Prints "8"
|
|
|
|
|
let x = 42;
|
|
|
|
|
println!("{}", x); // Prints "42"
|
|
|
|
|
```
|
|
|
|
|
|
|
|
|
|
Shadowing and mutable bindings may appear as two sides of the same coin, but
|
|
|
|
|
they are two distinct concepts that can't always be used interchangeably. For
|
|
|
|
|
one, shadowing enables us to rebind a name to a value of a different type. It
|
|
|
|
|
is also possible to change the mutability of a binding.
|
|
|
|
|
|
|
|
|
|
```rust
|
|
|
|
|
let mut x: i32 = 1;
|
|
|
|
|
x = 7;
|
|
|
|
|
let x = x; // x is now immutable and is bound to 7
|
|
|
|
|
|
|
|
|
|
let y = 4;
|
|
|
|
|
let y = "I can also be bound to text!"; // y is now of a different type
|
|
|
|
|
```
|