]>
Commit | Line | Data |
---|---|---|
85aaf69f | 1 | % Variable Bindings |
1a4d82fc | 2 | |
bd371182 | 3 | Virtually every non-'Hello World’ Rust program uses *variable bindings*. They |
b039eaaf | 4 | bind some value to a name, so it can be used later. `let` is |
9cc50fc6 | 5 | used to introduce a binding, like this: |
1a4d82fc | 6 | |
9346a6ac | 7 | ```rust |
1a4d82fc JJ |
8 | fn main() { |
9 | let x = 5; | |
10 | } | |
11 | ``` | |
12 | ||
9346a6ac AL |
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. | |
1a4d82fc | 16 | |
b039eaaf SL |
17 | # Patterns |
18 | ||
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 | |
54a0048b | 21 | left-hand side of a `let` statement is a ‘[pattern][pattern]’, not a |
b039eaaf | 22 | variable name. This means we can do things like: |
1a4d82fc | 23 | |
9346a6ac | 24 | ```rust |
1a4d82fc JJ |
25 | let (x, y) = (1, 2); |
26 | ``` | |
27 | ||
54a0048b | 28 | After this statement is evaluated, `x` will be one, and `y` will be two. |
9346a6ac | 29 | Patterns are really powerful, and have [their own section][pattern] in the |
9cc50fc6 | 30 | book. We don’t need those features for now, so we’ll keep this in the back |
9346a6ac AL |
31 | of our minds as we go forward. |
32 | ||
33 | [pattern]: patterns.html | |
1a4d82fc | 34 | |
b039eaaf SL |
35 | # Type annotations |
36 | ||
1a4d82fc | 37 | Rust is a statically typed language, which means that we specify our types up |
9346a6ac AL |
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 | |
3157f602 XL |
40 | out what the type of something is, Rust doesn’t require you to explicitly type |
41 | it out. | |
1a4d82fc JJ |
42 | |
43 | We can add the type if we want to, though. Types come after a colon (`:`): | |
44 | ||
9346a6ac | 45 | ```rust |
1a4d82fc JJ |
46 | let x: i32 = 5; |
47 | ``` | |
48 | ||
9346a6ac AL |
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`.” | |
1a4d82fc | 51 | |
85aaf69f SL |
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 | |
55 | bits. | |
56 | ||
1a4d82fc JJ |
57 | In future examples, we may annotate the type in a comment. The examples will |
58 | look like this: | |
59 | ||
9346a6ac | 60 | ```rust |
1a4d82fc JJ |
61 | fn main() { |
62 | let x = 5; // x: i32 | |
63 | } | |
64 | ``` | |
65 | ||
9346a6ac AL |
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 | |
69 | infers are. | |
1a4d82fc | 70 | |
b039eaaf SL |
71 | # Mutability |
72 | ||
85aaf69f | 73 | By default, bindings are *immutable*. This code will not compile: |
1a4d82fc | 74 | |
9346a6ac | 75 | ```rust,ignore |
1a4d82fc JJ |
76 | let x = 5; |
77 | x = 10; | |
78 | ``` | |
79 | ||
80 | It will give you this error: | |
81 | ||
82 | ```text | |
83 | error: re-assignment of immutable variable `x` | |
84 | x = 10; | |
85 | ^~~~~~~ | |
86 | ``` | |
87 | ||
88 | If you want a binding to be mutable, you can use `mut`: | |
89 | ||
9346a6ac | 90 | ```rust |
1a4d82fc JJ |
91 | let mut x = 5; // mut x: i32 |
92 | x = 10; | |
93 | ``` | |
94 | ||
95 | There is no single reason that bindings are immutable by default, but we can | |
9346a6ac | 96 | think about it through one of Rust’s primary focuses: safety. If you forget to |
1a4d82fc JJ |
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`. | |
101 | ||
9346a6ac | 102 | There are other good reasons to avoid mutable state when possible, but they’re |
1a4d82fc JJ |
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 | |
9346a6ac | 105 | what you need, so it’s not verboten. |
1a4d82fc | 106 | |
b039eaaf SL |
107 | # Initializing bindings |
108 | ||
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 | |
111 | use them. | |
1a4d82fc | 112 | |
9346a6ac | 113 | Let’s try it out. Change your `src/main.rs` file to look like this: |
1a4d82fc | 114 | |
9346a6ac | 115 | ```rust |
1a4d82fc JJ |
116 | fn main() { |
117 | let x: i32; | |
118 | ||
119 | println!("Hello world!"); | |
120 | } | |
121 | ``` | |
122 | ||
9346a6ac AL |
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!": | |
1a4d82fc JJ |
125 | |
126 | ```text | |
127 | Compiling hello_world v0.0.1 (file:///home/you/projects/hello_world) | |
5bcae85e | 128 | src/main.rs:2:9: 2:10 warning: unused variable: `x`, #[warn(unused_variables)] |
9346a6ac | 129 | on by default |
1a4d82fc JJ |
130 | src/main.rs:2 let x: i32; |
131 | ^ | |
132 | ``` | |
133 | ||
9346a6ac AL |
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: | |
1a4d82fc | 137 | |
9346a6ac | 138 | ```rust,ignore |
1a4d82fc JJ |
139 | fn main() { |
140 | let x: i32; | |
141 | ||
142 | println!("The value of x is: {}", x); | |
143 | } | |
144 | ``` | |
145 | ||
9346a6ac | 146 | And try to build it. You’ll get an error: |
1a4d82fc | 147 | |
9346a6ac | 148 | ```bash |
1a4d82fc JJ |
149 | $ cargo build |
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); | |
153 | ^ | |
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`. | |
160 | ``` | |
161 | ||
3157f602 XL |
162 | Rust will not let us use a value that has not been initialized. |
163 | ||
164 | Let take a minute to talk about this stuff we've added to `println!`. | |
1a4d82fc JJ |
165 | |
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 | |
85aaf69f | 168 | of value. *String interpolation* is a computer science term that means "stick |
1a4d82fc | 169 | in the middle of a string." We add a comma, and then `x`, to indicate that we |
9346a6ac AL |
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. | |
172 | ||
9cc50fc6 | 173 | When you use the curly braces, Rust will attempt to display the value in a |
9346a6ac AL |
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]. | |
9cc50fc6 | 176 | For now, we'll stick to the default: integers aren't very complicated to |
9346a6ac AL |
177 | print. |
178 | ||
179 | [format]: ../std/fmt/index.html | |
b039eaaf SL |
180 | |
181 | # Scope and shadowing | |
182 | ||
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: | |
189 | ||
190 | ```rust,ignore | |
191 | fn main() { | |
192 | let x: i32 = 17; | |
193 | { | |
194 | let y: i32 = 3; | |
195 | println!("The value of x is {} and value of y is {}", x, y); | |
196 | } | |
197 | println!("The value of x is {} and value of y is {}", x, y); // This won't work | |
198 | } | |
199 | ``` | |
200 | ||
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: | |
205 | ||
206 | ```bash | |
207 | $ cargo build | |
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 | |
211 | ^ | |
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`. | |
221 | ||
222 | To learn more, run the command again with --verbose. | |
223 | ``` | |
224 | ||
225 | Additionally, variable bindings can be shadowed. This means that a later | |
3157f602 XL |
226 | variable binding with the same name as another binding that is currently in |
227 | scope will override the previous binding. | |
b039eaaf SL |
228 | |
229 | ```rust | |
230 | let x: i32 = 8; | |
231 | { | |
232 | println!("{}", x); // Prints "8" | |
233 | let x = 12; | |
234 | println!("{}", x); // Prints "12" | |
235 | } | |
236 | println!("{}", x); // Prints "8" | |
237 | let x = 42; | |
238 | println!("{}", x); // Prints "42" | |
239 | ``` | |
240 | ||
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 | |
3157f602 XL |
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 | |
247 | by any means. | |
b039eaaf SL |
248 | |
249 | ```rust | |
250 | let mut x: i32 = 1; | |
251 | x = 7; | |
252 | let x = x; // x is now immutable and is bound to 7 | |
253 | ||
254 | let y = 4; | |
255 | let y = "I can also be bound to text!"; // y is now of a different type | |
256 | ``` |