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, 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` statement is a ‘[pattern][pattern]’, not a
22 variable name. This means we can do things like:
28 After this statement 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 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 explicitly type
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_variables)]
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.
164 Let us take a minute to talk about this stuff we've added to `println!`.
166 If you include two curly braces (`{}`, some call them moustaches...) in your
167 string to print, Rust will interpret this as a request to interpolate some sort
168 of value. *String interpolation* is a computer science term that means "stick
169 in the middle of a string." We add a comma, and then `x`, to indicate that we
170 want `x` to be the value we’re interpolating. The comma is used to separate
171 arguments we pass to functions and macros, if you’re passing more than one.
173 When you use the curly braces, Rust will attempt to display the value in a
174 meaningful way by checking out its type. If you want to specify the format in a
175 more detailed manner, there are a [wide number of options available][format].
176 For now, we'll stick to the default: integers aren't very complicated to
179 [format]: ../std/fmt/index.html
181 # Scope and shadowing
183 Let’s get back to bindings. Variable bindings have a scope - they are
184 constrained to live in a block they were defined in. A block is a collection
185 of statements enclosed by `{` and `}`. Function definitions are also blocks!
186 In the following example we define two variable bindings, `x` and `y`, which
187 live in different blocks. `x` can be accessed from inside the `fn main() {}`
188 block, while `y` can be accessed only from inside the inner block:
195 println!("The value of x is {} and value of y is {}", x, y);
197 println!("The value of x is {} and value of y is {}", x, y); // This won't work
201 The first `println!` would print "The value of x is 17 and the value of y is
202 3", but this example cannot be compiled successfully, because the second
203 `println!` cannot access the value of `y`, since it is not in scope anymore.
204 Instead we get this error:
208 Compiling hello v0.1.0 (file:///home/you/projects/hello_world)
209 main.rs:7:62: 7:63 error: unresolved name `y`. Did you mean `x`? [E0425]
210 main.rs:7 println!("The value of x is {} and value of y is {}", x, y); // This won't work
212 note: in expansion of format_args!
213 <std macros>:2:25: 2:56 note: expansion site
214 <std macros>:1:1: 2:62 note: in expansion of print!
215 <std macros>:3:1: 3:54 note: expansion site
216 <std macros>:1:1: 3:58 note: in expansion of println!
217 main.rs:7:5: 7:65 note: expansion site
218 main.rs:7:62: 7:63 help: run `rustc --explain E0425` to see a detailed explanation
219 error: aborting due to previous error
220 Could not compile `hello`.
222 To learn more, run the command again with --verbose.
225 Additionally, variable bindings can be shadowed. This means that a later
226 variable binding with the same name as another binding that is currently in
227 scope will override the previous binding.
232 println!("{}", x); // Prints "8"
234 println!("{}", x); // Prints "12"
236 println!("{}", x); // Prints "8"
238 println!("{}", x); // Prints "42"
241 Shadowing and mutable bindings may appear as two sides of the same coin, but
242 they are two distinct concepts that can't always be used interchangeably. For
243 one, shadowing enables us to rebind a name to a value of a different type. It
244 is also possible to change the mutability of a binding. Note that shadowing a
245 name does not alter or destroy the value it was bound to, and the value will
246 continue to exist until it goes out of scope, even if it is no longer accessible
252 let x = x; // x is now immutable and is bound to 7
255 let y = "I can also be bound to text!"; // y is now of a different type