]>
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 | |
40 | out what the type of something is, Rust doesn’t require you to actually type it | |
41 | 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) | |
9346a6ac AL |
128 | src/main.rs:2:9: 2:10 warning: unused variable: `x`, #[warn(unused_variable)] |
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 | ||
9346a6ac | 162 | Rust will not let us use a value that has not been initialized. Next, let’s |
1a4d82fc JJ |
163 | talk about this stuff we've added to `println!`. |
164 | ||
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 | |
85aaf69f | 167 | of value. *String interpolation* is a computer science term that means "stick |
1a4d82fc | 168 | in the middle of a string." We add a comma, and then `x`, to indicate that we |
9346a6ac AL |
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. | |
171 | ||
9cc50fc6 | 172 | When you use the curly braces, Rust will attempt to display the value in a |
9346a6ac AL |
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]. | |
9cc50fc6 | 175 | For now, we'll stick to the default: integers aren't very complicated to |
9346a6ac AL |
176 | print. |
177 | ||
178 | [format]: ../std/fmt/index.html | |
b039eaaf SL |
179 | |
180 | # Scope and shadowing | |
181 | ||
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: | |
188 | ||
189 | ```rust,ignore | |
190 | fn main() { | |
191 | let x: i32 = 17; | |
192 | { | |
193 | let y: i32 = 3; | |
194 | println!("The value of x is {} and value of y is {}", x, y); | |
195 | } | |
196 | println!("The value of x is {} and value of y is {}", x, y); // This won't work | |
197 | } | |
198 | ``` | |
199 | ||
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: | |
204 | ||
205 | ```bash | |
206 | $ cargo build | |
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 | |
210 | ^ | |
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`. | |
220 | ||
221 | To learn more, run the command again with --verbose. | |
222 | ``` | |
223 | ||
224 | Additionally, 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. | |
227 | ||
228 | ```rust | |
229 | let x: i32 = 8; | |
230 | { | |
231 | println!("{}", x); // Prints "8" | |
232 | let x = 12; | |
233 | println!("{}", x); // Prints "12" | |
234 | } | |
235 | println!("{}", x); // Prints "8" | |
236 | let x = 42; | |
237 | println!("{}", x); // Prints "42" | |
238 | ``` | |
239 | ||
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. | |
244 | ||
245 | ```rust | |
246 | let mut x: i32 = 1; | |
247 | x = 7; | |
248 | let x = x; // x is now immutable and is bound to 7 | |
249 | ||
250 | let y = 4; | |
251 | let y = "I can also be bound to text!"; // y is now of a different type | |
252 | ``` |