Rollup merge of #24247 - steveklabnik:update_variable_bindings, r=huonw
keeping on with the edits
This commit is contained in:
commit
0f1723b2b7
@ -1,44 +1,48 @@
|
||||
% Variable Bindings
|
||||
|
||||
The first thing we'll learn about are *variable bindings*. They look like this:
|
||||
Vitually every non-’Hello World’ Rust program uses *variable bindings*. They
|
||||
look like this:
|
||||
|
||||
```{rust}
|
||||
```rust
|
||||
fn main() {
|
||||
let x = 5;
|
||||
}
|
||||
```
|
||||
|
||||
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.
|
||||
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.
|
||||
|
||||
In many languages, this is called a *variable*. But Rust's variable bindings
|
||||
have a few tricks up their sleeves. Rust has a very powerful feature called
|
||||
*pattern matching* that we'll get into detail with later, but the left
|
||||
hand side of a `let` expression is a full pattern, not just a variable name.
|
||||
This means we can do things like:
|
||||
In many languages, this is called a *variable*, but Rust’s variable bindings
|
||||
have a few tricks up their sleeves. For example the left-hand side of a `let`
|
||||
expression is a ‘[pattern][pattern]’, not just a variable name. This means we
|
||||
can do things like:
|
||||
|
||||
```{rust}
|
||||
```rust
|
||||
let (x, y) = (1, 2);
|
||||
```
|
||||
|
||||
After this expression is evaluated, `x` will be one, and `y` will be two.
|
||||
Patterns are really powerful, but this is about all we can do with them so far.
|
||||
So let's just keep this in the back of our minds as we go forward.
|
||||
Patterns are really powerful, and have [their own section][pattern] in the
|
||||
book. We don’t need those features for now, so we’ll just keep this in the back
|
||||
of our minds as we go forward.
|
||||
|
||||
[pattern]: patterns.html
|
||||
|
||||
Rust is a statically typed language, which means that we specify our types up
|
||||
front. 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.
|
||||
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.
|
||||
|
||||
We can add the type if we want to, though. Types come after a colon (`:`):
|
||||
|
||||
```{rust}
|
||||
```rust
|
||||
let x: i32 = 5;
|
||||
```
|
||||
|
||||
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`."
|
||||
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`.”
|
||||
|
||||
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
|
||||
@ -48,19 +52,20 @@ bits.
|
||||
In future examples, we may annotate the type in a comment. The examples will
|
||||
look like this:
|
||||
|
||||
```{rust}
|
||||
```rust
|
||||
fn main() {
|
||||
let x = 5; // x: i32
|
||||
}
|
||||
```
|
||||
|
||||
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.
|
||||
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.
|
||||
|
||||
By default, bindings are *immutable*. This code will not compile:
|
||||
|
||||
```{ignore}
|
||||
```rust,ignore
|
||||
let x = 5;
|
||||
x = 10;
|
||||
```
|
||||
@ -75,30 +80,30 @@ error: re-assignment of immutable variable `x`
|
||||
|
||||
If you want a binding to be mutable, you can use `mut`:
|
||||
|
||||
```{rust}
|
||||
```rust
|
||||
let mut x = 5; // mut x: i32
|
||||
x = 10;
|
||||
```
|
||||
|
||||
There is no single reason that bindings are immutable by default, but we can
|
||||
think about it through one of Rust's primary focuses: safety. If you forget to
|
||||
think about it through one of Rust’s primary focuses: safety. If you forget to
|
||||
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`.
|
||||
|
||||
There are other good reasons to avoid mutable state when possible, but they're
|
||||
There are other good reasons to avoid mutable state when possible, but they’re
|
||||
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
|
||||
what you need, so it's not verboten.
|
||||
what you need, so it’s not verboten.
|
||||
|
||||
Let's get back to bindings. Rust variable bindings have one more aspect that
|
||||
Let’s get back to 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.
|
||||
|
||||
Let's try it out. Change your `src/main.rs` file to look like this:
|
||||
Let’s try it out. Change your `src/main.rs` file to look like this:
|
||||
|
||||
```{rust}
|
||||
```rust
|
||||
fn main() {
|
||||
let x: i32;
|
||||
|
||||
@ -106,21 +111,22 @@ fn main() {
|
||||
}
|
||||
```
|
||||
|
||||
You can use `cargo build` on the command line to build it. You'll get a warning,
|
||||
but it will still print "Hello, world!":
|
||||
You can use `cargo build` on the command line to build it. You’ll get a
|
||||
warning, but it will still print "Hello, world!":
|
||||
|
||||
```text
|
||||
Compiling hello_world v0.0.1 (file:///home/you/projects/hello_world)
|
||||
src/main.rs:2:9: 2:10 warning: unused variable: `x`, #[warn(unused_variable)] on by default
|
||||
src/main.rs:2:9: 2:10 warning: unused variable: `x`, #[warn(unused_variable)]
|
||||
on by default
|
||||
src/main.rs:2 let x: i32;
|
||||
^
|
||||
```
|
||||
|
||||
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:
|
||||
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:
|
||||
|
||||
```{rust,ignore}
|
||||
```rust,ignore
|
||||
fn main() {
|
||||
let x: i32;
|
||||
|
||||
@ -128,9 +134,9 @@ fn main() {
|
||||
}
|
||||
```
|
||||
|
||||
And try to build it. You'll get an error:
|
||||
And try to build it. You’ll get an error:
|
||||
|
||||
```{bash}
|
||||
```bash
|
||||
$ 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`
|
||||
@ -144,18 +150,20 @@ error: aborting due to previous error
|
||||
Could not compile `hello_world`.
|
||||
```
|
||||
|
||||
Rust will not let us use a value that has not been initialized. Next, let's
|
||||
Rust will not let us use a value that has not been initialized. Next, let’s
|
||||
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
|
||||
of value. *String interpolation* is a computer science term that means "stick
|
||||
in the middle of a string." We add a comma, and then `x`, to indicate that we
|
||||
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.
|
||||
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.
|
||||
|
||||
When you just use the curly braces, Rust will attempt to display the
|
||||
value in a 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](../std/fmt/index.html). For now, we'll just stick to the default:
|
||||
integers aren't very complicated to print.
|
||||
When you just use the curly braces, Rust will attempt to display the value in a
|
||||
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].
|
||||
For now, we'll just stick to the default: integers aren't very complicated to
|
||||
print.
|
||||
|
||||
[format]: ../std/fmt/index.html
|
||||
|
Loading…
x
Reference in New Issue
Block a user