3 Virtually every non-'Hello World’ Rust program uses *variable bindings*. They
4 bind some value to a name, so it can be used later. `let` is
5 used to introduce a binding, just like this:
13 Putting `fn main() {` in each example is a bit tedious, so we’ll leave that out
14 in the future. If you’re following along, make sure to edit your `main()`
15 function, rather than leaving it off. Otherwise, you’ll get an error.
19 In many languages, a variable binding would be called a *variable*, but Rust’s
20 variable bindings have a few tricks up their sleeves. For example the
21 left-hand side of a `let` expression is a ‘[pattern][pattern]’, not just a
22 variable name. This means we can do things like:
28 After this expression is evaluated, `x` will be one, and `y` will be two.
29 Patterns are really powerful, and have [their own section][pattern] in the
30 book. We don’t need those features for now, so we’ll just keep this in the back
31 of our minds as we go forward.
33 [pattern]: patterns.html
37 Rust is a statically typed language, which means that we specify our types up
38 front, and they’re checked at compile time. So why does our first example
39 compile? Well, Rust has this thing called ‘type inference’. If it can figure
40 out what the type of something is, Rust doesn’t require you to actually type it
43 We can add the type if we want to, though. Types come after a colon (`:`):
49 If I asked you to read this out loud to the rest of the class, you’d say “`x`
50 is a binding with the type `i32` and the value `five`.”
52 In this case we chose to represent `x` as a 32-bit signed integer. Rust has
53 many different primitive integer types. They begin with `i` for signed integers
54 and `u` for unsigned integers. The possible integer sizes are 8, 16, 32, and 64
57 In future examples, we may annotate the type in a comment. The examples will
66 Note the similarities between this annotation and the syntax you use with
67 `let`. Including these kinds of comments is not idiomatic Rust, but we'll
68 occasionally include them to help you understand what the types that Rust
73 By default, bindings are *immutable*. This code will not compile:
80 It will give you this error:
83 error: re-assignment of immutable variable `x`
88 If you want a binding to be mutable, you can use `mut`:
91 let mut x = 5; // mut x: i32
95 There is no single reason that bindings are immutable by default, but we can
96 think about it through one of Rust’s primary focuses: safety. If you forget to
97 say `mut`, the compiler will catch it, and let you know that you have mutated
98 something you may not have intended to mutate. If bindings were mutable by
99 default, the compiler would not be able to tell you this. If you _did_ intend
100 mutation, then the solution is quite easy: add `mut`.
102 There are other good reasons to avoid mutable state when possible, but they’re
103 out of the scope of this guide. In general, you can often avoid explicit
104 mutation, and so it is preferable in Rust. That said, sometimes, mutation is
105 what you need, so it’s not verboten.
107 # Initializing bindings
109 Rust variable bindings have one more aspect that differs from other languages:
110 bindings are required to be initialized with a value before you're allowed to
113 Let’s try it out. Change your `src/main.rs` file to look like this:
119 println!("Hello world!");
123 You can use `cargo build` on the command line to build it. You’ll get a
124 warning, but it will still print "Hello, world!":
127 Compiling hello_world v0.0.1 (file:///home/you/projects/hello_world)
128 src/main.rs:2:9: 2:10 warning: unused variable: `x`, #[warn(unused_variable)]
130 src/main.rs:2 let x: i32;
134 Rust warns us that we never use the variable binding, but since we never use
135 it, no harm, no foul. Things change if we try to actually use this `x`,
136 however. Let’s do that. Change your program to look like this:
142 println!("The value of x is: {}", x);
146 And try to build it. You’ll get an error:
150 Compiling hello_world v0.0.1 (file:///home/you/projects/hello_world)
151 src/main.rs:4:39: 4:40 error: use of possibly uninitialized variable: `x`
152 src/main.rs:4 println!("The value of x is: {}", x);
154 note: in expansion of format_args!
155 <std macros>:2:23: 2:77 note: expansion site
156 <std macros>:1:1: 3:2 note: in expansion of println!
157 src/main.rs:4:5: 4:42 note: expansion site
158 error: aborting due to previous error
159 Could not compile `hello_world`.
162 Rust will not let us use a value that has not been initialized. Next, let’s
163 talk about this stuff we've added to `println!`.
165 If you include two curly braces (`{}`, some call them moustaches...) in your
166 string to print, Rust will interpret this as a request to interpolate some sort
167 of value. *String interpolation* is a computer science term that means "stick
168 in the middle of a string." We add a comma, and then `x`, to indicate that we
169 want `x` to be the value we’re interpolating. The comma is used to separate
170 arguments we pass to functions and macros, if you’re passing more than one.
172 When you just use the curly braces, Rust will attempt to display the value in a
173 meaningful way by checking out its type. If you want to specify the format in a
174 more detailed manner, there are a [wide number of options available][format].
175 For now, we'll just stick to the default: integers aren't very complicated to
178 [format]: ../std/fmt/index.html
180 # Scope and shadowing
182 Let’s get back to bindings. Variable bindings have a scope - they are
183 constrained to live in a block they were defined in. A block is a collection
184 of statements enclosed by `{` and `}`. Function definitions are also blocks!
185 In the following example we define two variable bindings, `x` and `y`, which
186 live in different blocks. `x` can be accessed from inside the `fn main() {}`
187 block, while `y` can be accessed only from inside the inner block:
194 println!("The value of x is {} and value of y is {}", x, y);
196 println!("The value of x is {} and value of y is {}", x, y); // This won't work
200 The first `println!` would print "The value of x is 17 and the value of y is
201 3", but this example cannot be compiled successfully, because the second
202 `println!` cannot access the value of `y`, since it is not in scope anymore.
203 Instead we get this error:
207 Compiling hello v0.1.0 (file:///home/you/projects/hello_world)
208 main.rs:7:62: 7:63 error: unresolved name `y`. Did you mean `x`? [E0425]
209 main.rs:7 println!("The value of x is {} and value of y is {}", x, y); // This won't work
211 note: in expansion of format_args!
212 <std macros>:2:25: 2:56 note: expansion site
213 <std macros>:1:1: 2:62 note: in expansion of print!
214 <std macros>:3:1: 3:54 note: expansion site
215 <std macros>:1:1: 3:58 note: in expansion of println!
216 main.rs:7:5: 7:65 note: expansion site
217 main.rs:7:62: 7:63 help: run `rustc --explain E0425` to see a detailed explanation
218 error: aborting due to previous error
219 Could not compile `hello`.
221 To learn more, run the command again with --verbose.
224 Additionaly, variable bindings can be shadowed. This means that a later
225 variable binding with the same name as another binding, that's currently in
226 scope, will override the previous binding.
231 println!("{}", x); // Prints "8"
233 println!("{}", x); // Prints "12"
235 println!("{}", x); // Prints "8"
237 println!("{}", x); // Prints "42"
240 Shadowing and mutable bindings may appear as two sides of the same coin, but
241 they are two distinct concepts that can't always be used interchangeably. For
242 one, shadowing enables us to rebind a name to a value of a different type. It
243 is also possible to change the mutability of a binding.
248 let x = x; // x is now immutable and is bound to 7
251 let y = "I can also be bound to text!"; // y is now of a different type