4 # Common Programming Concepts
6 This chapter covers concepts that appear in almost every programming language
7 and how they work in Rust. Many programming languages have much in common at
8 their core. None of the concepts presented in this chapter are unique to Rust,
9 but we’ll discuss them in the context of Rust and explain the conventions
10 around using these concepts.
12 Specifically, you’ll learn about variables, basic types, functions, comments,
13 and control flow. These foundations will be in every Rust program, and learning
14 them early will give you a strong core to start from.
18 > The Rust language has a set of *keywords* that are reserved for use by
19 > the language only, much as in other languages. Keep in mind that you cannot
20 > use these words as names of variables or functions. Most of the keywords have
21 > special meanings, and you’ll be using them to do various tasks in your Rust
22 > programs; a few have no current functionality associated with them but have
23 > been reserved for functionality that might be added to Rust in the future. You
24 > can find a list of the keywords in Appendix A.
26 ## Variables and Mutability
28 As mentioned in the “Storing Values with Variables” section, by default
29 variables are immutable. This is one of many nudges Rust gives you to write
30 your code in a way that takes advantage of the safety and easy concurrency that
31 Rust offers. However, you still have the option to make your variables mutable.
32 Let’s explore how and why Rust encourages you to favor immutability and why
33 sometimes you might want to opt out.
35 When a variable is immutable, once a value is bound to a name, you can’t change
36 that value. To illustrate this, let’s generate a new project called *variables*
37 in your *projects* directory by using `cargo new variables`.
39 Then, in your new *variables* directory, open *src/main.rs* and replace its
40 code with the following code. This code won’t compile just yet, we'll first
41 examine the immutability error.
48 println!("The value of x is: {}", x);
50 println!("The value of x is: {}", x);
54 Save and run the program using `cargo run`. You should receive an error
55 message, as shown in this output:
59 Compiling variables v0.1.0 (file:///projects/variables)
60 error[E0384]: cannot assign twice to immutable variable `x`
66 | first assignment to `x`
67 | help: consider making this binding mutable: `mut x`
68 3 | println!("The value of x is: {}", x);
70 | ^^^^^ cannot assign twice to immutable variable
73 This example shows how the compiler helps you find errors in your programs.
74 Compiler errors can be frustrating, but really they only mean your program
75 isn’t safely doing what you want it to do yet; they do *not* mean that you’re
76 not a good programmer! Experienced Rustaceans still get compiler errors.
78 The error message indicates that the cause of the error is that you `` cannot
79 assign twice to immutable variable `x` ``, because you tried to assign a second
80 value to the immutable `x` variable.
82 It’s important that we get compile-time errors when we attempt to change a
83 value that’s designated as immutable because this very situation can lead to
84 bugs. If one part of our code operates on the assumption that a value will
85 never change and another part of our code changes that value, it’s possible
86 that the first part of the code won’t do what it was designed to do. The cause
87 of this kind of bug can be difficult to track down after the fact, especially
88 when the second piece of code changes the value only *sometimes*. The Rust
89 compiler guarantees that when you state a value won’t change, it really won’t
90 change, so you don’t have to keep track of it yourself. Your code is thus
91 easier to reason through.
93 But mutability can be very useful, and can make code more convenient to write.
94 Variables are immutable only by default; as you did in Chapter 2, you can make
95 them mutable by adding `mut` in front of the variable name. Adding `mut` also
96 conveys intent to future readers of the code by indicating that other parts of
97 the code will be changing this variable’s value.
99 For example, let’s change *src/main.rs* to the following:
101 Filename: src/main.rs
106 println!("The value of x is: {}", x);
108 println!("The value of x is: {}", x);
112 When we run the program now, we get this:
116 Compiling variables v0.1.0 (file:///projects/variables)
117 Finished dev [unoptimized + debuginfo] target(s) in 0.30s
118 Running `target/debug/variables`
123 We’re allowed to change the value that `x` binds to from `5` to `6` when `mut`
124 is used. There are multiple trade-offs to consider in addition to the
125 prevention of bugs. For example, in cases where you’re using large data
126 structures, mutating an instance in place may be faster than copying and
127 returning newly allocated instances. With smaller data structures, creating new
128 instances and writing in a more functional programming style may be easier to
129 think through, so lower performance might be a worthwhile penalty for gaining
134 Like immutable variables, *constants* are values that are bound to a name and
135 are not allowed to change, but there are a few differences between constants
138 First, you aren’t allowed to use `mut` with constants. Constants aren’t just
139 immutable by default—they’re always immutable. You declare constants using the
140 `const` keyword instead of the `let` keyword, and the type of the value *must*
141 be annotated. We’re about to cover types and type annotations in the next
142 section, “Data Types,” so don’t worry about the details right now. Just know
143 that you must always annotate the type.
145 Constants can be declared in any scope, including the global scope, which makes
146 them useful for values that many parts of code need to know about.
148 The last difference is that constants may be set only to a constant expression,
149 not the result of a value that could only be computed at runtime.
151 Here’s an example of a constant declaration:
154 const THREE_HOURS_IN_SECONDS: u32 = 60 * 60 * 3;
157 The constant’s name is `THREE_HOURS_IN_SECONDS` and its value is set to the
158 result of multiplying 60 (the number of seconds in a minute) by 60 (the number
159 of minutes in an hour) by 3 (the number of hours we want to count in this
160 program). Rust’s naming convention for constants is to use all uppercase with
161 underscores between words. The compiler is able to evaluate a limited set of
162 operations at compile time, which lets us choose to write out this value in a
163 way that’s easier to understand and verify, rather than setting this constant
164 to the value 10,800. See the Rust Reference’s section on constant evaluation at
165 *https://doc.rust-lang.org/reference/const_eval.html* for more information on
166 what operations can be used when declaring constants.
168 Constants are valid for the entire time a program runs, within the scope they
169 were declared in. This property makes constants useful for values in your
170 application domain that multiple parts of the program might need to know about,
171 such as the maximum number of points any player of a game is allowed to earn or
174 Naming hardcoded values used throughout your program as constants is useful in
175 conveying the meaning of that value to future maintainers of the code. It also
176 helps to have only one place in your code you would need to change if the
177 hardcoded value needed to be updated in the future.
181 As you saw in the guessing game tutorial in Chapter 2, you can declare a new
182 variable with the same name as a previous variable. Rustaceans say that the
183 first variable is *shadowed* by the second, which means that the second
184 variable’s value is what the program sees when the variable is used. We can
185 shadow a variable by using the same variable’s name and repeating the use of
186 the `let` keyword as follows:
188 Filename: src/main.rs
198 println!("The value of x in the inner scope is: {}", x);
201 println!("The value of x is: {}", x);
205 This program first binds `x` to a value of `5`. Then it shadows `x` by
206 repeating `let x =`, taking the original value and adding `1` so the value of
207 `x` is then `6`. Then, within an inner scope, the third `let` statement also
208 shadows `x`, multiplying the previous value by `2` to give `x` a value of `12`.
209 When that scope is over, the inner shadowing ends and `x` returns to being `6`.
210 When we run this program, it will output the following:
214 Compiling variables v0.1.0 (file:///projects/variables)
215 Finished dev [unoptimized + debuginfo] target(s) in 0.31s
216 Running `target/debug/variables`
217 The value of x in the inner scope is: 12
221 Shadowing is different from marking a variable as `mut`, because we’ll get a
222 compile-time error if we accidentally try to reassign to this variable without
223 using the `let` keyword. By using `let`, we can perform a few transformations
224 on a value but have the variable be immutable after those transformations have
227 <!--- so, to be clear, we're not overwriting the variable, so when the
228 shadowing variable goes out of scope the earlier variables become visible to
230 <!-- Well, we *are* overwriting it *in the inner scope* -- there's no way to
231 access the original value from the outer scope within the inner scope after
232 the shadowing. But yes, shadowing only applies to the scope it happens in,
233 which is what this example illustrates. Is there something that could be
234 made clearer? /Carol -->
236 The other difference between `mut` and shadowing is that because we’re
237 effectively creating a new variable when we use the `let` keyword again, we can
238 change the type of the value but reuse the same name. For example, say our
239 program asks a user to show how many spaces they want between some text by
240 inputting space characters, and then we want to store that input as a number:
244 let spaces = spaces.len();
247 The first `spaces` variable is a string type and the second `spaces` variable
248 is a number type. Shadowing thus spares us from having to come up with
249 different names, such as `spaces_str` and `spaces_num`; instead, we can reuse
250 the simpler `spaces` name. However, if we try to use `mut` for this, as shown
251 here, we’ll get a compile-time error:
254 let mut spaces = " ";
255 spaces = spaces.len();
258 The error says we’re not allowed to mutate a variable’s type:
262 Compiling variables v0.1.0 (file:///projects/variables)
263 error[E0308]: mismatched types
266 3 | spaces = spaces.len();
267 | ^^^^^^^^^^^^ expected `&str`, found `usize`
270 Now that we’ve explored how variables work, let’s look at more data types they
275 Every value in Rust is of a certain *data type*, which tells Rust what kind of
276 data is being specified so it knows how to work with that data. We’ll look at
277 two data type subsets: scalar and compound.
279 Keep in mind that Rust is a *statically typed* language, which means that it
280 must know the types of all variables at compile time. The compiler can usually
281 infer what type we want to use based on the value and how we use it. In cases
282 when many types are possible, such as when we converted a `String` to a numeric
283 type using `parse` in the “Comparing the Guess to the Secret Number” section in
284 Chapter 2, we must add a type annotation, like this:
287 let guess: u32 = "42".parse().expect("Not a number!");
290 If we don’t add the type annotation here, Rust will display the following
291 error, which means the compiler needs more information from us to know which
296 Compiling no_type_annotations v0.1.0 (file:///projects/no_type_annotations)
297 error[E0282]: type annotations needed
300 2 | let guess = "42".parse().expect("Not a number!");
301 | ^^^^^ consider giving `guess` a type
304 You’ll see different type annotations for other data types.
308 A *scalar* type represents a single value. Rust has four primary scalar types:
309 integers, floating-point numbers, Booleans, and characters. You may recognize
310 these from other programming languages. Let’s jump into how they work in Rust.
314 An *integer* is a number without a fractional component. We used one integer
315 type in Chapter 2, the `u32` type. This type declaration indicates that the
316 value it’s associated with should be an unsigned integer (signed integer types
317 start with `i`, instead of `u`) that takes up 32 bits of space. Table 3-1 shows
318 the built-in integer types in Rust. We can use any of these variants to declare
319 the type of an integer value.
321 Table 3-1: Integer Types in Rust
323 | Length | Signed | Unsigned |
324 |---------|---------|----------|
325 | 8-bit | `i8` | `u8` |
326 | 16-bit | `i16` | `u16` |
327 | 32-bit | `i32` | `u32` |
328 | 64-bit | `i64` | `u64` |
329 | 128-bit | `i128` | `u128` |
330 | arch | `isize` | `usize` |
332 Each variant can be either signed or unsigned and has an explicit size.
333 *Signed* and *unsigned* refer to whether it’s possible for the number to be
334 negative—in other words, whether the number needs to have a sign with it
335 (signed) or whether it will only ever be positive and can therefore be
336 represented without a sign (unsigned). It’s like writing numbers on paper: when
337 the sign matters, a number is shown with a plus sign or a minus sign; however,
338 when it’s safe to assume the number is positive, it’s shown with no sign.
339 Signed numbers are stored using two’s complement representation.
341 Each signed variant can store numbers from -(2<sup>n - 1</sup>) to 2<sup>n -
342 1</sup> - 1 inclusive, where *n* is the number of bits that variant uses. So an
343 `i8` can store numbers from -(2<sup>7</sup>) to 2<sup>7</sup> - 1, which equals
344 -128 to 127. Unsigned variants can store numbers from 0 to 2<sup>n</sup> - 1,
345 so a `u8` can store numbers from 0 to 2<sup>8</sup> - 1, which equals 0 to 255.
347 Additionally, the `isize` and `usize` types depend on the architecture of the
348 computer your program is running on, which is denoted in the table as "arch":
349 64 bits if you’re on a 64-bit architecture and 32 bits if you’re on a 32-bit
352 <!--- what does arch refer to? /LC --->
353 <!-- architecture-dependent, I've tried to specifically make that connection,
354 is this better? /Carol -->
356 You can write integer literals in any of the forms shown in Table 3-2. Note
357 that number literals that can be multiple numeric types allow a type suffix,
358 such as `57u8`, to designate the type. Number literals can also use `_` as a
359 visual separator to make the number easier to read, such as `1_000`, which will
360 have the same value as if you had specified `1000`.
362 Table 3-2: Integer Literals in Rust
364 | Number literals | Example |
365 |------------------|---------------|
366 | Decimal | `98_222` |
369 | Binary | `0b1111_0000` |
370 | Byte (`u8` only) | `b'A'` |
372 So how do you know which type of integer to use? If you’re unsure, Rust’s
373 defaults are generally good places to start: integer types default to `i32`.
374 The primary situation in which you’d use `isize` or `usize` is when indexing
375 some sort of collection.
377 > ##### Integer Overflow
379 > Let’s say you have a variable of type `u8` that can hold values between 0 and
380 > 255. If you try to change the variable to a value outside of that range, such
381 > as 256, *integer overflow* will occur, which can result in one of two
382 > behaviors. When you’re compiling in debug mode, Rust includes checks for
383 > integer overflow that cause your program to *panic* at runtime if this
384 > behavior occurs. Rust uses the term panicking when a program exits with an
385 > error; we’ll discuss panics in more depth in the “Unrecoverable Errors with
386 > `panic!`” section in Chapter 9.
388 > When you’re compiling in release mode with the `--release` flag, Rust does
389 > *not* include checks for integer overflow that cause panics. Instead, if
390 > overflow occurs, Rust performs *two’s complement wrapping*. In short, values
391 > greater than the maximum value the type can hold “wrap around” to the minimum
392 > of the values the type can hold. In the case of a `u8`, the value 256 becomes
393 > 0, the value 257 becomes 1, and so on. The program won’t panic, but the
394 > variable will have a value that probably isn’t what you were expecting it to
395 > have. Relying on integer overflow’s wrapping behavior is considered an error.
397 > To explicitly handle the possibility of overflow, you can use these families
398 > of methods provided by the standard library for primitive numeric types:
400 > - Wrap in all modes with the `wrapping_*` methods, such as `wrapping_add`
401 > - Return the `None` value if there is overflow with the `checked_*` methods
402 > - Return the value and a boolean indicating whether there was overflow with
403 > the `overflowing_*` methods
404 > - Saturate at the value’s minimum or maximum values with `saturating_*`
407 #### Floating-Point Types
409 Rust also has two primitive types for *floating-point numbers*, which are
410 numbers with decimal points. Rust’s floating-point types are `f32` and `f64`,
411 which are 32 bits and 64 bits in size, respectively. The default type is `f64`
412 because on modern CPUs it’s roughly the same speed as `f32` but is capable of
413 more precision. All floating-point types are signed.
415 <!--- and these don't need to be designate as signed or unsigned? /LC --->
416 <!-- Yes, it's a long story why, I've added a quick statement as such at the
417 end of the previous paragraph, does that work? /Carol-->
419 Here’s an example that shows floating-point numbers in action:
421 Filename: src/main.rs
427 let y: f32 = 3.0; // f32
431 Floating-point numbers are represented according to the IEEE-754 standard. The
432 `f32` type is a single-precision float, and `f64` has double precision.
434 #### Numeric Operations
436 Rust supports the basic mathematical operations you’d expect for all of the
437 number types: addition, subtraction, multiplication, division, and remainder.
438 Integer division rounds down to the nearest integer. The following code shows
439 how you’d use each numeric operation in a `let` statement:
441 Filename: src/main.rs
449 let difference = 95.5 - 4.3;
452 let product = 4 * 30;
455 let quotient = 56.7 / 32.2;
456 let floored = 2 / 3; // Results in 0
459 let remainder = 43 % 5;
463 Each expression in these statements uses a mathematical operator and evaluates
464 to a single value, which is then bound to a variable. Appendix B contains a
465 list of all operators that Rust provides.
467 #### The Boolean Type
469 As in most other programming languages, a Boolean type in Rust has two possible
470 values: `true` and `false`. Booleans are one byte in size. The Boolean type in
471 Rust is specified using `bool`. For example:
473 Filename: src/main.rs
479 let f: bool = false; // with explicit type annotation
483 The main way to use Boolean values is through conditionals, such as an `if`
484 expression. We’ll cover how `if` expressions work in Rust in the “Control
487 #### The Character Type
489 Rust’s `char` type is the language’s most primitive alphabetic type. Here's
490 some examples of declaring `char` values:
492 Filename: src/main.rs
498 let heart_eyed_cat = '😻';
502 Note that we specify `char` literals with single quotes, as opposed to string
503 literals, which use double quotes. Rust’s `char` type is four bytes in size and
504 represents a Unicode Scalar Value, which means it can represent a lot more than
505 just ASCII. Accented letters; Chinese, Japanese, and Korean characters; emoji;
506 and zero-width spaces are all valid `char` values in Rust. Unicode Scalar
507 Values range from `U+0000` to `U+D7FF` and `U+E000` to `U+10FFFF` inclusive.
508 However, a “character” isn’t really a concept in Unicode, so your human
509 intuition for what a “character” is may not match up with what a `char` is in
510 Rust. We’ll discuss this topic in detail in “Storing UTF-8 Encoded Text with
511 Strings” in Chapter 8.
515 *Compound types* can group multiple values into one type. Rust has two
516 primitive compound types: tuples and arrays.
520 A tuple is a general way of grouping together a number of values with a variety
521 of types into one compound type. Tuples have a fixed length: once declared,
522 they cannot grow or shrink in size.
524 We create a tuple by writing a comma-separated list of values inside
525 parentheses. Each position in the tuple has a type, and the types of the
526 different values in the tuple don’t have to be the same. We’ve added optional
527 type annotations in this example:
529 Filename: src/main.rs
533 let tup: (i32, f64, u8) = (500, 6.4, 1);
537 The variable `tup` binds to the entire tuple, because a tuple is considered a
538 single compound element. To get the individual values out of a tuple, we can
539 use pattern matching to destructure a tuple value, like this:
541 Filename: src/main.rs
545 let tup = (500, 6.4, 1);
549 println!("The value of y is: {}", y);
553 This program first creates a tuple and binds it to the variable `tup`. It then
554 uses a pattern with `let` to take `tup` and turn it into three separate
555 variables, `x`, `y`, and `z`. This is called *destructuring*, because it breaks
556 the single tuple into three parts. Finally, the program prints the value of
559 We can also access a tuple element directly by using a period (`.`) followed by
560 the index of the value we want to access. For example:
562 Filename: src/main.rs
566 let x: (i32, f64, u8) = (500, 6.4, 1);
568 let five_hundred = x.0;
570 let six_point_four = x.1;
576 This program creates the tuple `x` and then makes new variables for each
577 element by using their respective indices. As with most programming languages,
578 the first index in a tuple is 0.
580 The tuple without any values, `()`, is a special type that has only one value,
581 also written `()`. The type is called the *unit type* and the value is called
582 the *unit value*. Expressions implicitly return the unit value if they don’t
583 return any other value.
587 Another way to have a collection of multiple values is with an *array*. Unlike
588 a tuple, every element of an array must have the same type. Unlike arrays in
589 some other languages, arrays in Rust have a fixed length.
591 We write the values in an array as a comma-separated list inside square
594 Filename: src/main.rs
598 let a = [1, 2, 3, 4, 5];
602 Arrays are useful when you want your data allocated on the stack rather than
603 the heap (we will discuss the stack and the heap more in Chapter 4) or when you
604 want to ensure you always have a fixed number of elements. An array isn’t as
605 flexible as the vector type, though. A vector is a similar collection type
606 provided by the standard library that *is* allowed to grow or shrink in size.
607 If you’re unsure whether to use an array or a vector, chances are you should
608 use a vector. Chapter 8 discusses vectors in more detail.
610 However, arrays are more useful when you know the number of elements will not
611 need to change. For example, if you were using the names of the month in a
612 program, you would probably use an array rather than a vector because you know
613 it will always contain 12 elements:
616 let months = ["January", "February", "March", "April", "May", "June", "July",
617 "August", "September", "October", "November", "December"];
620 <!--- and is the benefit here that using the array prevents other coders making
621 the mistake of somehow changing the values, while with a vector they could?
623 <!-- No, the benefit is that you know there will always be 12 elements in the
624 array. Arrays can be mutable in that other parts of the code could change
625 "January" to "Jan", but they couldn't add or remove a month. Does that make
626 sense? I've changed the paragraph before the code to say "number of elements"
627 instead of "values", does that clear it up? /Carol -->
629 You write an array’s type using square brackets with the type of each element,
630 a semicolon, and then the number of elements in the array, like so:
633 let a: [i32; 5] = [1, 2, 3, 4, 5];
636 Here, `i32` is the type of each element. After the semicolon, the number `5`
637 indicates the array contains five elements.
639 You can also initialize an array to contain the same value for each element by
640 specifying the initial value, followed by a semicolon, and then the length of
641 the array in square brackets, as shown here:
647 The array named `a` will contain `5` elements that will all be set to the value
648 `3` initially. This is the same as writing `let a = [3, 3, 3, 3, 3];` but in a
651 ##### Accessing Array Elements
653 An array is a single chunk of memory of a known, fixed size that can be
654 allocated on the stack. You can access elements of an array using indexing,
657 Filename: src/main.rs
661 let a = [1, 2, 3, 4, 5];
668 In this example, the variable named `first` will get the value `1`, because
669 that is the value at index `[0]` in the array. The variable named `second` will
670 get the value `2` from index `[1]` in the array.
672 ##### Invalid Array Element Access
674 Let's see what happens if you try to access an element of an array that is past
675 the end of the array. Say you run this code, similar to the guessing game in
676 Chapter 2, to get an array index from the user:
678 Filename: src/main.rs
684 let a = [1, 2, 3, 4, 5];
686 println!("Please enter an array index.");
688 let mut index = String::new();
691 .read_line(&mut index)
692 .expect("Failed to read line");
694 let index: usize = index
697 .expect("Index entered was not a number");
699 let element = a[index];
702 "The value of the element at index {} is: {}",
708 This code compiles successfully. If you run this code using `cargo run` and
709 enter 0, 1, 2, 3, or 4, the program will print out the corresponding value at
710 that index in the array. If you instead enter a number past the end of the
711 array, such as 10, you’ll see output like this:
714 thread 'main' panicked at 'index out of bounds: the len is 5 but the index is 10', src/main.rs:19:19
715 note: run with `RUST_BACKTRACE=1` environment variable to display a backtrace
718 The program resulted in a *runtime* error at the point of using an invalid
719 value in the indexing operation. The program exited with an error message and
720 didn’t execute the final `println!` statement. When you attempt to access an
721 element using indexing, Rust will check that the index you’ve specified is less
722 than the array length. If the index is greater than or equal to the length,
723 Rust will panic. This check has to happen at runtime, especially in this case,
724 because the compiler can’t possibly know what value a user will enter when they
727 This is an example of Rust’s memory safety principles in action. In many
728 low-level languages, this kind of check is not done, and when you provide an
729 incorrect index, invalid memory can be accessed. Rust protects you against this
730 kind of error by immediately exiting instead of allowing the memory access and
731 continuing. Chapter 9 discusses more of Rust’s error handling.
735 Functions are prevalent in Rust code. You’ve already seen one of the most
736 important functions in the language: the `main` function, which is the entry
737 point of many programs. You’ve also seen the `fn` keyword, which allows you to
738 declare new functions.
740 Rust code uses *snake case* as the conventional style for function and variable
741 names, in which all letters are lowercase and underscores separate words.
742 Here’s a program that contains an example function definition:
744 Filename: src/main.rs
748 println!("Hello, world!");
753 fn another_function() {
754 println!("Another function.");
758 We define a function in Rust by entering `fn` followed by a function name and a
759 set of parentheses. The curly brackets tell the compiler where the function
760 body begins and ends.
762 We can call any function we’ve defined by entering its name followed by a set
763 of parentheses. Because `another_function` is defined in the program, it can be
764 called from inside the `main` function. Note that we defined `another_function`
765 *after* the `main` function in the source code; we could have defined it before
766 as well. Rust doesn’t care where you define your functions, only that they’re
769 Let’s start a new binary project named *functions* to explore functions
770 further. Place the `another_function` example in *src/main.rs* and run it. You
771 should see the following output:
775 Compiling functions v0.1.0 (file:///projects/functions)
776 Finished dev [unoptimized + debuginfo] target(s) in 0.28s
777 Running `target/debug/functions`
782 The lines execute in the order in which they appear in the `main` function.
783 First, the “Hello, world!” message prints, and then `another_function` is
784 called and its message is printed.
788 We can define functions to have *parameters*, which are special variables that
789 are part of a function’s signature. When a function has parameters, you can
790 provide it with concrete values for those parameters. Technically, the concrete
791 values are called *arguments*, but in casual conversation, people tend to use
792 the words *parameter* and *argument* interchangeably for either the variables
793 in a function’s definition or the concrete values passed in when you call a
796 In this version of `another_function` we add a parameter:
798 Filename: src/main.rs
805 fn another_function(x: i32) {
806 println!("The value of x is: {}", x);
810 Try running this program; you should get the following output:
814 Compiling functions v0.1.0 (file:///projects/functions)
815 Finished dev [unoptimized + debuginfo] target(s) in 1.21s
816 Running `target/debug/functions`
820 The declaration of `another_function` has one parameter named `x`. The type of
821 `x` is specified as `i32`. When we pass `5` in to `another_function`, the
822 `println!` macro puts `5` where the pair of curly brackets were in the format
825 In function signatures, you *must* declare the type of each parameter. This is
826 a deliberate decision in Rust’s design: requiring type annotations in function
827 definitions means the compiler almost never needs you to use them elsewhere in
828 the code to figure out what type you mean.
830 When defining multiple parameters, separate the parameter declarations with
833 Filename: src/main.rs
837 print_labeled_measurement(5, 'h');
840 fn print_labeled_measurement(value: i32, unit_label: char) {
841 println!("The measurement is: {}{}", value, unit_label);
845 This example creates a function named `print_labeled_measurement` with two
846 parameters. The first parameter is named `value` and is an `i32`. The second is
847 named `unit_label` and is type `char`. The function then prints text containing
848 both the `value` and the `unit_label`.
850 Let’s try running this code. Replace the program currently in your *functions*
851 project’s *src/main.rs* file with the preceding example and run it using `cargo
856 Compiling functions v0.1.0 (file:///projects/functions)
857 Finished dev [unoptimized + debuginfo] target(s) in 0.31s
858 Running `target/debug/functions`
859 The measurement is: 5h
862 Because we called the function with `5` as the value for `value` and `'h'` as
863 the value for `unit_label`, the program output contains those values.
865 ### Statements and Expressions
867 Function bodies are made up of a series of statements optionally ending in an
868 expression. So far, the functions we've covered haven't included an ending
869 expression, but you have seen an expression as part of a statement. Because
870 Rust is an expression-based language, this is an important distinction to
871 understand. Other languages don’t have the same distinctions, so let’s look at
872 what statements and expressions are and how their differences affect the bodies
875 *Statements* are instructions that perform some action and do not return a
876 value. *Expressions* evaluate to a resulting value. Let’s look at some examples.
878 We’ve actually already used statements and expressions. Creating a variable and
879 assigning a value to it with the `let` keyword is a statement. In Listing 3-1,
880 `let y = 6;` is a statement.
882 Filename: src/main.rs
890 Listing 3-1: A `main` function declaration containing one statement
892 Function definitions are also statements; the entire preceding example is a
895 Statements do not return values. Therefore, you can’t assign a `let` statement
896 to another variable, as the following code tries to do; you’ll get an error:
898 Filename: src/main.rs
906 When you run this program, the error you’ll get looks like this:
910 Compiling functions v0.1.0 (file:///projects/functions)
911 error[E0658]: `let` expressions in this position are experimental
914 2 | let x = (let y = 6);
917 = note: see issue #53667 <https://github.com/rust-lang/rust/issues/53667> for more information
918 = help: you can write `matches!(<expr>, <pattern>)` instead of `let <pattern> = <expr>`
920 error: expected expression, found statement (`let`)
923 2 | let x = (let y = 6);
926 = note: variable declaration using `let` is a statement
928 warning: unnecessary parentheses around assigned value
931 2 | let x = (let y = 6);
932 | ^^^^^^^^^^^ help: remove these parentheses
934 = note: `#[warn(unused_parens)]` on by default
937 The `let y = 6` statement does not return a value, so there isn’t anything for
938 `x` to bind to. This is different from what happens in other languages, such as
939 C and Ruby, where the assignment returns the value of the assignment. In those
940 languages, you can write `x = y = 6` and have both `x` and `y` have the value
941 `6`; that is not the case in Rust.
943 Expressions evaluate to a value and make up most of the rest of the code that
944 you’ll write in Rust. Consider a math operation, such as `5 + 6`, which is an
945 expression that evaluates to the value `11`. Expressions can be part of
946 statements: in Listing 3-1, the `6` in the statement `let y = 6;` is an
947 expression that evaluates to the value `6`. Calling a function is an
948 expression. Calling a macro is an expression. A new scope block created with
949 curly brackets is an expression, for example:
951 Filename: src/main.rs
962 println!("The value of y is: {}", y);
975 is a block that, in this case, evaluates to `4`. That value gets bound to `y`
976 as part of the `let` statement. Note that the `x + 1` line doesn't have a
977 semicolon at the end, unlike most of the lines you’ve seen so far. Expressions
978 do not include ending semicolons. If you add a semicolon to the end of an
979 expression, you turn it into a statement, and it will then not return a value.
980 Keep this in mind as you explore function return values and expressions next.
982 ### Functions with Return Values
984 Functions can return values to the code that calls them. We don’t name return
985 values, but we do declare their type after an arrow (`->`). In Rust, the return
986 value of the function is synonymous with the value of the final expression in
987 the block of the body of a function. You can return early from a function by
988 using the `return` keyword and specifying a value, but most functions return
989 the last expression implicitly. Here’s an example of a function that returns a
992 Filename: src/main.rs
1002 println!("The value of x is: {}", x);
1006 There are no function calls, macros, or even `let` statements in the `five`
1007 function—just the number `5` by itself. That’s a perfectly valid function in
1008 Rust. Note that the function’s return type is specified too, as `-> i32`. Try
1009 running this code; the output should look like this:
1013 Compiling functions v0.1.0 (file:///projects/functions)
1014 Finished dev [unoptimized + debuginfo] target(s) in 0.30s
1015 Running `target/debug/functions`
1016 The value of x is: 5
1019 The `5` in `five` is the function’s return value, which is why the return type
1020 is `i32`. Let’s examine this in more detail. There are two important bits:
1021 first, the line `let x = five();` shows that we’re using the return value of a
1022 function to initialize a variable. Because the function `five` returns a `5`,
1023 that line is the same as the following:
1029 Second, the `five` function has no parameters and defines the type of the
1030 return value, but the body of the function is a lonely `5` with no semicolon
1031 because it’s an expression whose value we want to return.
1033 Let’s look at another example:
1035 Filename: src/main.rs
1039 let x = plus_one(5);
1041 println!("The value of x is: {}", x);
1044 fn plus_one(x: i32) -> i32 {
1049 Running this code will print `The value of x is: 6`. But if we place a
1050 semicolon at the end of the line containing `x + 1`, changing it from an
1051 expression to a statement, we’ll get an error.
1053 Filename: src/main.rs
1057 let x = plus_one(5);
1059 println!("The value of x is: {}", x);
1062 fn plus_one(x: i32) -> i32 {
1067 Compiling this code produces an error, as follows:
1071 Compiling functions v0.1.0 (file:///projects/functions)
1072 error[E0308]: mismatched types
1073 --> src/main.rs:7:24
1075 7 | fn plus_one(x: i32) -> i32 {
1076 | -------- ^^^ expected `i32`, found `()`
1078 | implicitly returns `()` as its body has no tail or `return` expression
1080 | - help: consider removing this semicolon
1083 The main error message, “mismatched types,” reveals the core issue with this
1084 code. The definition of the function `plus_one` says that it will return an
1085 `i32`, but statements don’t evaluate to a value, which is expressed by `()`,
1086 the unit type. Therefore, nothing is returned, which contradicts the function
1087 definition and results in an error. In this output, Rust provides a message to
1088 possibly help rectify this issue: it suggests removing the semicolon, which
1089 would fix the error.
1093 All programmers strive to make their code easy to understand, but sometimes
1094 extra explanation is warranted. In these cases, programmers leave *comments* in
1095 their source code that the compiler will ignore but people reading the source
1096 code may find useful.
1098 Here’s a simple comment:
1104 In Rust, the idiomatic comment style starts a comment with two slashes, and the
1105 comment continues until the end of the line. For comments that extend beyond a
1106 single line, you’ll need to include `//` on each line, like this:
1109 // So we’re doing something complicated here, long enough that we need
1110 // multiple lines of comments to do it! Whew! Hopefully, this comment will
1111 // explain what’s going on.
1114 Comments can also be placed at the end of lines containing code:
1116 Filename: src/main.rs
1120 let lucky_number = 7; // I’m feeling lucky today
1124 But you’ll more often see them used in this format, with the comment on a
1125 separate line above the code it’s annotating:
1127 Filename: src/main.rs
1131 // I’m feeling lucky today
1132 let lucky_number = 7;
1136 Rust also has another kind of comment, documentation comments, which we’ll
1137 discuss in the “Publishing a Crate to Crates.io” section of Chapter 14.
1141 The ability to run some code depending on if a condition is true, or run some
1142 code repeatedly while a condition is true, are basic building blocks in most
1143 programming languages. The most common constructs that let you control the flow
1144 of execution of Rust code are `if` expressions and loops.
1146 ### `if` Expressions
1148 An `if` expression allows you to branch your code depending on conditions. You
1149 provide a condition and then state, “If this condition is met, run this block
1150 of code. If the condition is not met, do not run this block of code.”
1152 Create a new project called *branches* in your *projects* directory to explore
1153 the `if` expression. In the *src/main.rs* file, input the following:
1155 Filename: src/main.rs
1162 println!("condition was true");
1164 println!("condition was false");
1169 All `if` expressions start with the keyword `if`, followed by a condition. In
1170 this case, the condition checks whether or not the variable `number` has a
1171 value less than 5. We place block of code to execute if the condition is true
1172 immediately after the condition inside curly brackets. Blocks of code
1173 associated with the conditions in `if` expressions are sometimes called *arms*,
1174 just like the arms in `match` expressions that we discussed in the “Comparing
1175 the Guess to the Secret Number” section of Chapter 2.
1177 Optionally, we can also include an `else` expression, which we chose
1178 to do here, to give the program an alternative block of code to execute should
1179 the condition evaluate to false. If you don’t provide an `else` expression and
1180 the condition is false, the program will just skip the `if` block and move on
1181 to the next bit of code.
1183 Try running this code; you should see the following output:
1187 Compiling branches v0.1.0 (file:///projects/branches)
1188 Finished dev [unoptimized + debuginfo] target(s) in 0.31s
1189 Running `target/debug/branches`
1193 Let’s try changing the value of `number` to a value that makes the condition
1194 `false` to see what happens:
1200 Run the program again, and look at the output:
1204 Compiling branches v0.1.0 (file:///projects/branches)
1205 Finished dev [unoptimized + debuginfo] target(s) in 0.31s
1206 Running `target/debug/branches`
1210 It’s also worth noting that the condition in this code *must* be a `bool`. If
1211 the condition isn’t a `bool`, we’ll get an error. For example, try running the
1214 Filename: src/main.rs
1221 println!("number was three");
1226 The `if` condition evaluates to a value of `3` this time, and Rust throws an
1231 Compiling branches v0.1.0 (file:///projects/branches)
1232 error[E0308]: mismatched types
1236 | ^^^^^^ expected `bool`, found integer
1239 The error indicates that Rust expected a `bool` but got an integer. Unlike
1240 languages such as Ruby and JavaScript, Rust will not automatically try to
1241 convert non-Boolean types to a Boolean. You must be explicit and always provide
1242 `if` with a Boolean as its condition. If we want the `if` code block to run
1243 only when a number is not equal to `0`, for example, we can change the `if`
1244 expression to the following:
1246 Filename: src/main.rs
1253 println!("number was something other than zero");
1258 Running this code will print `number was something other than zero`.
1260 #### Handling Multiple Conditions with `else if`
1262 You can use multiple conditions by combining `if` and `else` in an `else if`
1263 expression. For example:
1265 Filename: src/main.rs
1271 if number % 4 == 0 {
1272 println!("number is divisible by 4");
1273 } else if number % 3 == 0 {
1274 println!("number is divisible by 3");
1275 } else if number % 2 == 0 {
1276 println!("number is divisible by 2");
1278 println!("number is not divisible by 4, 3, or 2");
1283 This program has four possible paths it can take. After running it, you should
1284 see the following output:
1288 Compiling branches v0.1.0 (file:///projects/branches)
1289 Finished dev [unoptimized + debuginfo] target(s) in 0.31s
1290 Running `target/debug/branches`
1291 number is divisible by 3
1294 When this program executes, it checks each `if` expression in turn and executes
1295 the first body for which the condition holds true. Note that even though 6 is
1296 divisible by 2, we don’t see the output `number is divisible by 2`, nor do we
1297 see the `number is not divisible by 4, 3, or 2` text from the `else` block.
1298 That’s because Rust only executes the block for the first true condition, and
1299 once it finds one, it doesn’t even check the rest.
1301 Using too many `else if` expressions can clutter your code, so if you have more
1302 than one, you might want to refactor your code. Chapter 6 describes a powerful
1303 Rust branching construct called `match` for these cases.
1305 #### Using `if` in a `let` Statement
1307 Because `if` is an expression, we can use it on the right side of a `let`
1308 statement to assign the outcome to a variable, as in Listing 3-2.
1310 Filename: src/main.rs
1314 let condition = true;
1315 let number = if condition { 5 } else { 6 };
1317 println!("The value of number is: {}", number);
1321 Listing 3-2: Assigning the result of an `if` expression
1324 The `number` variable will be bound to a value based on the outcome of the `if`
1325 expression. Run this code to see what happens:
1329 Compiling branches v0.1.0 (file:///projects/branches)
1330 Finished dev [unoptimized + debuginfo] target(s) in 0.30s
1331 Running `target/debug/branches`
1332 The value of number is: 5
1335 Remember that blocks of code evaluate to the last expression in them, and
1336 numbers by themselves are also expressions. In this case, the value of the
1337 whole `if` expression depends on which block of code executes. This means the
1338 values that have the potential to be results from each arm of the `if` must be
1339 the same type; in Listing 3-2, the results of both the `if` arm and the `else`
1340 arm were `i32` integers. If the types are mismatched, as in the following
1341 example, we’ll get an error:
1343 Filename: src/main.rs
1347 let condition = true;
1349 let number = if condition { 5 } else { "six" };
1351 println!("The value of number is: {}", number);
1355 When we try to compile this code, we’ll get an error. The `if` and `else` arms
1356 have value types that are incompatible, and Rust indicates exactly where to
1357 find the problem in the program:
1361 Compiling branches v0.1.0 (file:///projects/branches)
1362 error[E0308]: `if` and `else` have incompatible types
1363 --> src/main.rs:4:44
1365 4 | let number = if condition { 5 } else { "six" };
1366 | - ^^^^^ expected integer, found `&str`
1368 | expected because of this
1371 The expression in the `if` block evaluates to an integer, and the expression in
1372 the `else` block evaluates to a string. This won’t work because variables must
1373 have a single type, and Rust needs to know at compile time what type the
1374 `number` variable is, definitively. Knowing the type of `number` lets the
1375 compiler verify the type is valid everywhere we use `number`. Rust wouldn’t be
1376 able to do that if the type of `number` was only determined at runtime; the
1377 compiler would be more complex and would make fewer guarantees about the code
1378 if it had to keep track of multiple hypothetical types for any variable.
1380 ### Repetition with Loops
1382 It’s often useful to execute a block of code more than once. For this task,
1383 Rust provides several *loops*, which will run through the code inside the loop
1384 body to the end and then start immediately back at the beginning. To
1385 experiment with loops, let’s make a new project called *loops*.
1387 Rust has three kinds of loops: `loop`, `while`, and `for`. Let’s try each one.
1389 #### Repeating Code with `loop`
1391 The `loop` keyword tells Rust to execute a block of code over and over again
1392 forever or until you explicitly tell it to stop.
1394 As an example, change the *src/main.rs* file in your *loops* directory to look
1397 Filename: src/main.rs
1407 When we run this program, we’ll see `again!` printed over and over continuously
1408 until we stop the program manually. Most terminals support the keyboard shortcut
1409 <span class="keystroke">ctrl-c</span> to interrupt a program that is stuck in
1410 a continual loop. Give it a try:
1414 Compiling loops v0.1.0 (file:///projects/loops)
1415 Finished dev [unoptimized + debuginfo] target(s) in 0.29s
1416 Running `target/debug/loops`
1424 The symbol `^C` represents where you pressed <span class="keystroke">ctrl-c
1425 </span>. You may or may not see the word `again!` printed after the `^C`,
1426 depending on where the code was in the loop when it received the interrupt
1429 Fortunately, Rust also provides a way to break out of a loop using code. You can
1430 place the `break` keyword within the loop to tell the program when to stop
1431 executing the loop. Recall that we did this in the guessing game in the
1432 “Quitting After a Correct Guess” section of Chapter 2 to exit the program when
1433 the user won the game by guessing the correct number.
1435 We also used `continue` in the guessing game, which in a loop tells the program
1436 to skip over any remaining code in this iteration of the loop and go to the
1439 If you have loops within loops, `break` and `continue` apply to the innermost
1440 loop at that point. You can optionally specify a *loop label* on a loop that we
1441 can then use with `break` or `continue` to specify that those keywords apply to
1442 the labeled loop instead of the innermost loop. Here’s an example with two
1448 'counting_up: loop {
1449 println!("count = {}", count);
1450 let mut remaining = 10;
1453 println!("remaining = {}", remaining);
1465 println!("End count = {}", count);
1469 The outer loop has the label `'counting_up`, and it will count up from 0 to 2.
1470 The inner loop without a label counts down from 10 to 9. The first `break` that
1471 doesn’t specify a label will exit the inner loop only. The `break
1472 'counting_up;` statement will exit the outer loop. This code prints:
1475 Compiling loops v0.1.0 (file:///projects/loops)
1476 Finished dev [unoptimized + debuginfo] target(s) in 0.58s
1477 Running `target/debug/loops`
1489 #### Returning Values from Loops
1491 One of the uses of a `loop` is to retry an operation you know might fail, such
1492 as checking whether a thread has completed its job. You might also need to pass
1493 the result of that operation out of the loop to the rest of your code. To do
1494 this, you can add the value you want returned after the `break` expression you
1495 use to stop the loop; that value will be returned out of the loop so you can
1496 use it, as shown here:
1500 let mut counter = 0;
1510 println!("The result is {}", result);
1514 Before the loop, we declare a variable named `counter` and initialize it to
1515 `0`. Then we declare a variable named `result` to hold the value returned from
1516 the loop. On every iteration of the loop, we add `1` to the `counter` variable,
1517 and then check whether the counter is equal to `10`. When it is, we use the
1518 `break` keyword with the value `counter * 2`. After the loop, we use a
1519 semicolon to end the statement that assigns the value to `result`. Finally, we
1520 print the value in `result`, which in this case is 20.
1522 #### Conditional Loops with `while`
1524 A program will often need to evaluate a condition within a loop. While the
1525 condition is true, the loop runs. When the condition ceases to be true, the
1526 program calls `break`, stopping the loop. It's possible to implement behavior
1527 like this using a combination of `loop`, `if`, `else`, and `break`; you could
1528 try that now in a program, if you’d like. However, this pattern is so common
1529 that Rust has a built-in language construct for it, called a `while` loop. In
1530 Listing 3-3, we use `while` to loop the program three times, counting down each
1531 time, and then, after the loop, print a message and exit.
1533 Filename: src/main.rs
1540 println!("{}!", number);
1545 println!("LIFTOFF!!!");
1549 Listing 3-3: Using a `while` loop to run code while a condition holds true
1551 This construct eliminates a lot of nesting that would be necessary if you used
1552 `loop`, `if`, `else`, and `break`, and it’s clearer. While a condition holds
1553 true, the code runs; otherwise, it exits the loop.
1555 #### Looping Through a Collection with `for`
1557 You can choose to use the `while` construct to loop over the elements of a
1558 collection, such as an array. For example, the loop in Listing 3-4 prints each
1559 element in the array `a`.
1561 Filename: src/main.rs
1565 let a = [10, 20, 30, 40, 50];
1569 println!("the value is: {}", a[index]);
1576 Listing 3-4: Looping through each element of a collection using a `while` loop
1578 Here, the code counts up through the elements in the array. It starts at index
1579 `0`, and then loops until it reaches the final index in the array (that is,
1580 when `index < 5` is no longer true). Running this code will print every element
1585 Compiling loops v0.1.0 (file:///projects/loops)
1586 Finished dev [unoptimized + debuginfo] target(s) in 0.32s
1587 Running `target/debug/loops`
1595 All five array values appear in the terminal, as expected. Even though `index`
1596 will reach a value of `5` at some point, the loop stops executing before trying
1597 to fetch a sixth value from the array.
1599 However, this approach is error prone; we could cause the program to panic if
1600 the index value or test condition are incorrect. For example, if you changed
1601 the definition of the `a` array to have four elements but forgot to update the
1602 condition to `while index < 4`, the code would panic. It’s also slow, because
1603 the compiler adds runtime code to perform the conditional check of whether the
1604 index is within the bounds of the array on every iteration through the loop.
1606 As a more concise alternative, you can use a `for` loop and execute some code
1607 for each item in a collection. A `for` loop looks like the code in Listing 3-5.
1609 Filename: src/main.rs
1613 let a = [10, 20, 30, 40, 50];
1616 println!("the value is: {}", element);
1621 Listing 3-5: Looping through each element of a collection using a `for` loop
1623 When we run this code, we’ll see the same output as in Listing 3-4. More
1624 importantly, we’ve now increased the safety of the code and eliminated the
1625 chance of bugs that might result from going beyond the end of the array or not
1626 going far enough and missing some items.
1628 Using the `for` loop, you wouldn’t need to remember to change any other code if
1629 you changed the number of values in the array, as you would with the method
1630 used in Listing 3-4.
1632 The safety and conciseness of `for` loops make them the most commonly used loop
1633 construct in Rust. Even in situations in which you want to run some code a
1634 certain number of times, as in the countdown example that used a `while` loop
1635 in Listing 3-3, most Rustaceans would use a `for` loop. The way to do that
1636 would be to use a `Range`, provided by the standard library, which generates
1637 all numbers in sequence starting from one number and ending before another
1640 Here’s what the countdown would look like using a `for` loop and another method
1641 we’ve not yet talked about, `rev`, to reverse the range:
1643 Filename: src/main.rs
1647 for number in (1..4).rev() {
1648 println!("{}!", number);
1650 println!("LIFTOFF!!!");
1654 This code is a bit nicer, isn’t it?
1658 You made it! That was a sizable chapter: you learned about variables, scalar
1659 and compound data types, functions, comments, `if` expressions, and loops!
1660 To practice with the concepts discussed in this chapter, try building
1661 programs to do the following:
1663 * Convert temperatures between Fahrenheit and Celsius.
1664 * Generate the nth Fibonacci number.
1665 * Print the lyrics to the Christmas carol “The Twelve Days of Christmas,”
1666 taking advantage of the repetition in the song.
1668 When you’re ready to move on, we’ll talk about a concept in Rust that *doesn’t*
1669 commonly exist in other programming languages: ownership.