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 Chapter 2, by default variables are immutable. This is one of
29 many nudges Rust gives you to write your code in a way that takes advantage of
30 the safety and easy concurrency that Rust offers. However, you still have the
31 option to make your variables mutable. Let’s explore how and why Rust
32 encourages you to favor immutability and why sometimes you might want to opt
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 --bin variables`.
39 Then, in your new *variables* directory, open *src/main.rs* and replace its
40 code with the following code that won’t compile just yet:
47 println!("The value of x is: {}", x);
49 println!("The value of x is: {}", x);
53 Save and run the program using `cargo run`. You should receive an error
54 message, as shown in this output:
57 error[E0384]: cannot assign twice to immutable variable `x`
61 | - first assignment to `x`
62 3 | println!("The value of x is: {}", x);
64 | ^^^^^ cannot assign twice to immutable variable
67 This example shows how the compiler helps you find errors in your programs.
68 Even though compiler errors can be frustrating, they only mean your program
69 isn’t safely doing what you want it to do yet; they do *not* mean that you’re
70 not a good programmer! Experienced Rustaceans still get compiler errors.
72 The error indicates that the cause of the error is that you `cannot assign twice
73 to immutable variable x`, because you tried to assign a second value to the
74 immutable `x` variable.
76 It’s important that we get compile-time errors when we attempt to change a
77 value that we previously designated as immutable because this very situation
78 can lead to bugs. If one part of our code operates on the assumption that a
79 value will never change and another part of our code changes that value, it’s
80 possible that the first part of the code won’t do what it was designed to do.
81 The cause of this kind of bug can be difficult to track down after the fact,
82 especially when the second piece of code changes the value only *sometimes*.
84 In Rust, the compiler guarantees that when you state that a value won’t change,
85 it really won’t change. That means that when you’re reading and writing code,
86 you don’t have to keep track of how and where a value might change. Your code
87 is thus easier to reason through.
89 But mutability can be very useful. Variables are immutable only by default; as
90 you did in Chapter 2, you can make them mutable by adding `mut` in front of the
91 variable name. In addition to allowing this value to change, `mut` conveys
92 intent to future readers of the code by indicating that other parts of the code
93 will be changing this variable value.
95 For example, let’s change *src/main.rs* to the following:
102 println!("The value of x is: {}", x);
104 println!("The value of x is: {}", x);
108 When we run the program now, we get this:
112 Compiling variables v0.1.0 (file:///projects/variables)
113 Finished dev [unoptimized + debuginfo] target(s) in 0.30 secs
114 Running `target/debug/variables`
119 We’re allowed to change the value that `x` binds to from `5` to `6` when `mut`
120 is used. In some cases, you’ll want to make a variable mutable because it makes
121 the code more convenient to write than if it had only immutable variables.
123 There are multiple trade-offs to consider in addition to the prevention of
124 bugs. For example, in cases where you’re using large data structures, mutating
125 an instance in place may be faster than copying and returning newly allocated
126 instances. With smaller data structures, creating new instances and writing in
127 a more functional programming style may be easier to think through, so lower
128 performance might be a worthwhile penalty for gaining that clarity.
130 ### Differences Between Variables and Constants
132 Being unable to change the value of a variable might have reminded you of
133 another programming concept that most other languages have: *constants*. Like
134 immutable variables, constants are values that are bound to a name and are not
135 allowed to change, but there are a few differences between constants and
138 First, you aren’t allowed to use `mut` with constants. Constants aren’t just
139 immutable by default—they’re always immutable.
141 You declare constants using the `const` keyword instead of the `let` keyword,
142 and the type of the value *must* be annotated. We’re about to cover types and
143 type annotations in the next section, “Data Types,” so don’t worry about the
144 details right now. Just know that you must always annotate the type.
146 Constants can be declared in any scope, including the global scope, which makes
147 them useful for values that many parts of code need to know about.
149 The last difference is that constants may be set only to a constant expression,
150 not the result of a function call or any other value that could only be
153 Here’s an example of a constant declaration where the constant’s name is
154 `MAX_POINTS` and its value is set to 100,000. (Rust’s constant naming
155 convention is to use all uppercase with underscores between words):
158 const MAX_POINTS: u32 = 100_000;
161 Constants are valid for the entire time a program runs, within the scope they
162 were declared in, making them a useful choice for values in your application
163 domain that multiple parts of the program might need to know about, such as the
164 maximum number of points any player of a game is allowed to earn or the speed
167 Naming hardcoded values used throughout your program as constants is useful in
168 conveying the meaning of that value to future maintainers of the code. It also
169 helps to have only one place in your code you would need to change if the
170 hardcoded value needed to be updated in the future.
174 As you saw in the “Comparing the Guess to the Secret Number” section in Chapter
175 2, you can declare a new variable with the same name as a previous variable,
176 and the new variable shadows the previous variable. Rustaceans say that the
177 first variable is *shadowed* by the second, which means that the second
178 variable’s value is what appears when the variable is used. We can shadow a
179 variable by using the same variable’s name and repeating the use of the `let`
182 Filename: src/main.rs
192 println!("The value of x is: {}", x);
196 This program first binds `x` to a value of `5`. Then it shadows `x` by
197 repeating `let x =`, taking the original value and adding `1` so the value of
198 `x` is then `6`. The third `let` statement also shadows `x`, multiplying the
199 previous value by `2` to give `x` a final value of `12`. When we run this
200 program, it will output the following:
204 Compiling variables v0.1.0 (file:///projects/variables)
205 Finished dev [unoptimized + debuginfo] target(s) in 0.31 secs
206 Running `target/debug/variables`
207 The value of x is: 12
210 Shadowing is different than marking a variable as `mut`, because we’ll get a
211 compile-time error if we accidentally try to reassign to this variable without
212 using the `let` keyword. By using `let`, we can perform a few transformations
213 on a value but have the variable be immutable after those transformations have
216 The other difference between `mut` and shadowing is that because we’re
217 effectively creating a new variable when we use the `let` keyword again, we can
218 change the type of the value but reuse the same name. For example, say our
219 program asks a user to show how many spaces they want between some text by
220 inputting space characters, but we really want to store that input as a number:
224 let spaces = spaces.len();
227 This construct is allowed because the first `spaces` variable is a string type
228 and the second `spaces` variable, which is a brand-new variable that happens to
229 have the same name as the first one, is a number type. Shadowing thus spares us
230 from having to come up with different names, such as `spaces_str` and
231 `spaces_num`; instead, we can reuse the simpler `spaces` name. However, if we
232 try to use `mut` for this, as shown here, we’ll get a compile-time error:
235 let mut spaces = " ";
236 spaces = spaces.len();
239 The error says we’re not allowed to mutate a variable’s type:
242 error[E0308]: mismatched types
245 3 | spaces = spaces.len();
246 | ^^^^^^^^^^^^ expected &str, found usize
248 = note: expected type `&str`
252 Now that we’ve explored how variables work, let’s look at more data types they
257 Every value in Rust is of a certain *data type*, which tells Rust what kind of
258 data is being specified so it knows how to work with that data. We’ll look at
259 two data type subsets: scalar and compound.
261 Keep in mind that Rust is a *statically typed* language, which means that it
262 must know the types of all variables at compile time. The compiler can usually
263 infer what type we want to use based on the value and how we use it. In cases
264 when many types are possible, such as when we converted a `String` to a numeric
265 type using `parse` in the “Comparing the Guess to the Secret Number” section in
266 Chapter 2, we must add a type annotation, like this:
269 let guess: u32 = "42".parse().expect("Not a number!");
272 If we don’t add the type annotation here, Rust will display the following
273 error, which means the compiler needs more information from us to know which
277 error[E0282]: type annotations needed
280 2 | let guess = "42".parse().expect("Not a number!");
283 | cannot infer type for `_`
284 | consider giving `guess` a type
287 You’ll see different type annotations for other data types.
291 A *scalar* type represents a single value. Rust has four primary scalar types:
292 integers, floating-point numbers, Booleans, and characters. You may recognize
293 these from other programming languages. Let’s jump into how they work in Rust.
297 An *integer* is a number without a fractional component. We used one integer
298 type in Chapter 2, the `u32` type. This type declaration indicates that the
299 value it’s associated with should be an unsigned integer (signed integer types
300 start with `i`, instead of `u`) that takes up 32 bits of space. Table 3-1 shows
301 the built-in integer types in Rust. Each variant in the Signed and Unsigned
302 columns (for example, `i16`) can be used to declare the type of an integer
305 Table 3-1: Integer Types in Rust
307 | Length | Signed | Unsigned |
308 |--------|---------|----------|
309 | 8-bit | `i8` | `u8` |
310 | 16-bit | `i16` | `u16` |
311 | 32-bit | `i32` | `u32` |
312 | 64-bit | `i64` | `u64` |
313 | arch | `isize` | `usize` |
315 Each variant can be either signed or unsigned and has an explicit size.
316 *Signed* and *unsigned* refer to whether it’s possible for the number to be
317 negative or positive—in other words, whether the number needs to have a sign
318 with it (signed) or whether it will only ever be positive and can therefore be
319 represented without a sign (unsigned). It’s like writing numbers on paper: when
320 the sign matters, a number is shown with a plus sign or a minus sign; however,
321 when it’s safe to assume the number is positive, it’s shown with no sign.
322 Signed numbers are stored using two’s complement representation (if you’re
323 unsure what this is, you can search for it online; an explanation is outside
324 the scope of this book).
326 Each signed variant can store numbers from -(2<sup>n - 1</sup>) to 2<sup>n -
327 1</sup> - 1 inclusive, where *n* is the number of bits that variant uses. So an
328 `i8` can store numbers from -(2<sup>7</sup>) to 2<sup>7</sup> - 1, which equals
329 -128 to 127. Unsigned variants can store numbers from 0 to 2<sup>n</sup> - 1,
330 so a `u8` can store numbers from 0 to 2<sup>8</sup> - 1, which equals 0 to 255.
332 Additionally, the `isize` and `usize` types depend on the kind of computer your
333 program is running on: 64 bits if you’re on a 64-bit architecture and 32 bits
334 if you’re on a 32-bit architecture.
336 You can write integer literals in any of the forms shown in Table 3-2. Note
337 that all number literals except the byte literal allow a type suffix, such as
338 `57u8`, and `_` as a visual separator, such as `1_000`.
340 Table 3-2: Integer Literals in Rust
342 | Number literals | Example |
343 |------------------|---------------|
344 | Decimal | `98_222` |
347 | Binary | `0b1111_0000` |
348 | Byte (`u8` only) | `b'A'` |
350 So how do you know which type of integer to use? If you’re unsure, Rust’s
351 defaults are generally good choices, and integer types default to `i32`: this
352 type is generally the fastest, even on 64-bit systems. The primary situation in
353 which you’d use `isize` or `usize` is when indexing some sort of collection.
355 #### Floating-Point Types
357 Rust also has two primitive types for *floating-point numbers*, which are
358 numbers with decimal points. Rust’s floating-point types are `f32` and `f64`,
359 which are 32 bits and 64 bits in size, respectively. The default type is `f64`
360 because on modern CPUs it’s roughly the same speed as `f32` but is capable of
363 Here’s an example that shows floating-point numbers in action:
365 Filename: src/main.rs
371 let y: f32 = 3.0; // f32
375 Floating-point numbers are represented according to the IEEE-754 standard. The
376 `f32` type is a single-precision float, and `f64` has double precision.
378 #### Numeric Operations
380 Rust supports the basic mathematical operations you’d expect for all of the
381 number types: addition, subtraction, multiplication, division, and remainder.
382 The following code shows how you’d use each one in a `let` statement:
384 Filename: src/main.rs
392 let difference = 95.5 - 4.3;
395 let product = 4 * 30;
398 let quotient = 56.7 / 32.2;
401 let remainder = 43 % 5;
405 Each expression in these statements uses a mathematical operator and evaluates
406 to a single value, which is then bound to a variable. Appendix B contains a
407 list of all operators that Rust provides.
409 #### The Boolean Type
411 As in most other programming languages, a Boolean type in Rust has two possible
412 values: `true` and `false`. The Boolean type in Rust is specified using `bool`.
415 Filename: src/main.rs
421 let f: bool = false; // with explicit type annotation
425 The main way to consume Boolean values is through conditionals, such as an `if`
426 expression. We’ll cover how `if` expressions work in Rust in the “Control Flow”
429 #### The Character Type
431 So far we’ve worked only with numbers, but Rust supports letters too. Rust’s
432 `char` type is the language’s most primitive alphabetic type, and the following
433 code shows one way to use it. (Note that the `char` type is specified with
434 single quotes, as opposed to strings, which use double quotes.)
436 Filename: src/main.rs
442 let heart_eyed_cat = '😻';
446 Rust’s `char` type represents a Unicode Scalar Value, which means it can
447 represent a lot more than just ASCII. Accented letters; Chinese, Japanese, and
448 Korean ideographs; emoji; and zero-width spaces are all valid `char` types in
449 Rust. Unicode Scalar Values range from `U+0000` to `U+D7FF` and `U+E000` to
450 `U+10FFFF` inclusive. However, a “character” isn’t really a concept in Unicode,
451 so your human intuition for what a “character” is may not match up with what a
452 `char` is in Rust. We’ll discuss this topic in detail in “Strings” in Chapter 8.
456 *Compound types* can group multiple values into one type. Rust has two
457 primitive compound types: tuples and arrays.
461 A tuple is a general way of grouping together some number of other values with
462 a variety of types into one compound type.
464 We create a tuple by writing a comma-separated list of values inside
465 parentheses. Each position in the tuple has a type, and the types of the
466 different values in the tuple don’t have to be the same. We’ve added optional
467 type annotations in this example:
469 Filename: src/main.rs
473 let tup: (i32, f64, u8) = (500, 6.4, 1);
477 The variable `tup` binds to the entire tuple, because a tuple is considered a
478 single compound element. To get the individual values out of a tuple, we can
479 use pattern matching to destructure a tuple value, like this:
481 Filename: src/main.rs
485 let tup = (500, 6.4, 1);
489 println!("The value of y is: {}", y);
493 This program first creates a tuple and binds it to the variable `tup`. It then
494 uses a pattern with `let` to take `tup` and turn it into three separate
495 variables, `x`, `y`, and `z`. This is called *destructuring*, because it breaks
496 the single tuple into three parts. Finally, the program prints the value of
499 In addition to destructuring through pattern matching, we can access a tuple
500 element directly by using a period (`.`) followed by the index of the value we
501 want to access. For example:
503 Filename: src/main.rs
507 let x: (i32, f64, u8) = (500, 6.4, 1);
509 let five_hundred = x.0;
511 let six_point_four = x.1;
517 This program creates a tuple, `x`, and then makes new variables for each
518 element by using their index. As with most programming languages, the first
519 index in a tuple is 0.
523 Another way to have a collection of multiple values is with an *array*. Unlike
524 a tuple, every element of an array must have the same type. Arrays in Rust are
525 different from arrays in some other languages because arrays in Rust have a
526 fixed length: once declared, they cannot grow or shrink in size.
528 In Rust, the values going into an array are written as a comma-separated list
529 inside square brackets:
531 Filename: src/main.rs
535 let a = [1, 2, 3, 4, 5];
539 Arrays are useful when you want your data allocated on the stack rather than
540 the heap (we will discuss the stack and the heap more in Chapter 4), or when
541 you want to ensure you always have a fixed number of elements. An array isn’t
542 as flexible as the vector type, though. A vector is a similar collection type
543 provided by the standard library that *is* allowed to grow or shrink in size.
544 If you’re unsure whether to use an array or a vector, you should probably use a
545 vector. Chapter 8 discusses vectors in more detail.
547 An example of when you might want to use an array rather than a vector is in a
548 program that needs to know the names of the months of the year. It’s very
549 unlikely that such a program will need to add or remove months, so you can use
550 an array because you know it will always contain 12 items:
553 let months = ["January", "February", "March", "April", "May", "June", "July",
554 "August", "September", "October", "November", "December"];
557 ##### Accessing Array Elements
559 An array is a single chunk of memory allocated on the stack. You can access
560 elements of an array using indexing, like this:
562 Filename: src/main.rs
566 let a = [1, 2, 3, 4, 5];
573 In this example, the variable named `first` will get the value `1`, because
574 that is the value at index `[0]` in the array. The variable named `second` will
575 get the value `2` from index `[1]` in the array.
577 ##### Invalid Array Element Access
579 What happens if you try to access an element of an array that is past the end
580 of the array? Say you change the example to the following code, which will
581 compile but exit with an error when it runs:
583 Filename: src/main.rs
587 let a = [1, 2, 3, 4, 5];
590 let element = a[index];
592 println!("The value of element is: {}", element);
596 Running this code using `cargo run` produces the following result:
600 Compiling arrays v0.1.0 (file:///projects/arrays)
601 Finished dev [unoptimized + debuginfo] target(s) in 0.31 secs
602 Running `target/debug/arrays`
603 thread '<main>' panicked at 'index out of bounds: the len is 5 but the index is
605 note: Run with `RUST_BACKTRACE=1` for a backtrace.
608 The compilation didn’t produce any errors, but the program resulted in a
609 *runtime* error and didn’t exit successfully. When you attempt to access an
610 element using indexing, Rust will check that the index you’ve specified is less
611 than the array length. If the index is greater than the length, Rust will
612 *panic*, which is the term Rust uses when a program exits with an error.
614 This is the first example of Rust’s safety principles in action. In many
615 low-level languages, this kind of check is not done, and when you provide an
616 incorrect index, invalid memory can be accessed. Rust protects you against this
617 kind of error by immediately exiting instead of allowing the memory access and
618 continuing. Chapter 9 discusses more of Rust’s error handling.
622 Functions are pervasive in Rust code. You’ve already seen one of the most
623 important functions in the language: the `main` function, which is the entry
624 point of many programs. You’ve also seen the `fn` keyword, which allows you to
625 declare new functions.
627 Rust code uses *snake case* as the conventional style for function and variable
628 names. In snake case, all letters are lowercase and underscores separate words.
629 Here’s a program that contains an example function definition:
631 Filename: src/main.rs
635 println!("Hello, world!");
640 fn another_function() {
641 println!("Another function.");
645 Function definitions in Rust start with `fn` and have a set of parentheses
646 after the function name. The curly brackets tell the compiler where the
647 function body begins and ends.
649 We can call any function we’ve defined by entering its name followed by a set
650 of parentheses. Because `another_function` is defined in the program, it can be
651 called from inside the `main` function. Note that we defined `another_function`
652 *after* the `main` function in the source code; we could have defined it before
653 as well. Rust doesn’t care where you define your functions, only that they’re
656 Let’s start a new binary project named *functions* to explore functions
657 further. Place the `another_function` example in *src/main.rs* and run it. You
658 should see the following output:
662 Compiling functions v0.1.0 (file:///projects/functions)
663 Finished dev [unoptimized + debuginfo] target(s) in 0.28 secs
664 Running `target/debug/functions`
669 The lines execute in the order in which they appear in the `main` function.
670 First, the “Hello, world!” message prints, and then `another_function` is
671 called and its message is printed.
673 ### Function Parameters
675 Functions can also be defined to have *parameters*, which are special variables
676 that are part of a function’s signature. When a function has parameters, you
677 can provide it with concrete values for those parameters. Technically, the
678 concrete values are called *arguments*, but in casual conversation, people tend
679 to use the words *parameter* and *argument* interchangeably for either the
680 variables in a function’s definition or the concrete values passed in when you
683 The following rewritten version of `another_function` shows what parameters
686 Filename: src/main.rs
693 fn another_function(x: i32) {
694 println!("The value of x is: {}", x);
698 Try running this program; you should get the following output:
702 Compiling functions v0.1.0 (file:///projects/functions)
703 Finished dev [unoptimized + debuginfo] target(s) in 1.21 secs
704 Running `target/debug/functions`
708 The declaration of `another_function` has one parameter named `x`. The type of
709 `x` is specified as `i32`. When `5` is passed to `another_function`, the
710 `println!` macro puts `5` where the pair of curly brackets were in the format
713 In function signatures, you *must* declare the type of each parameter. This is
714 a deliberate decision in Rust’s design: requiring type annotations in function
715 definitions means the compiler almost never needs you to use them elsewhere in
716 the code to figure out what you mean.
718 When you want a function to have multiple parameters, separate the parameter
719 declarations with commas, like this:
721 Filename: src/main.rs
725 another_function(5, 6);
728 fn another_function(x: i32, y: i32) {
729 println!("The value of x is: {}", x);
730 println!("The value of y is: {}", y);
734 This example creates a function with two parameters, both of which are `i32`
735 types. The function then prints the values in both of its parameters. Note that
736 function parameters don’t all need to be the same type, they just happen to be
739 Let’s try running this code. Replace the program currently in your *functions*
740 project’s *src/main.rs* file with the preceding example and run it using `cargo
745 Compiling functions v0.1.0 (file:///projects/functions)
746 Finished dev [unoptimized + debuginfo] target(s) in 0.31 secs
747 Running `target/debug/functions`
752 Because we called the function with `5` as the value for `x` and `6` is passed
753 as the value for `y`, the two strings are printed with these values.
757 Function bodies are made up of a series of statements optionally ending in an
758 expression. So far, we’ve only covered functions without an ending expression,
759 but you have seen an expression as part of statements. Because Rust is an
760 expression-based language, this is an important distinction to understand.
761 Other languages don’t have the same distinctions, so let’s look at what
762 statements and expressions are and how their differences affect the bodies of
765 ### Statements and Expressions
767 We’ve actually already used statements and expressions. *Statements* are
768 instructions that perform some action and do not return a value. *Expressions*
769 evaluate to a resulting value. Let’s look at some examples.
771 Creating a variable and assigning a value to it with the `let` keyword is a
772 statement. In Listing 3-1, `let y = 6;` is a statement:
774 Filename: src/main.rs
782 Listing 3-1: A `main` function declaration containing one statement
784 Function definitions are also statements; the entire preceding example is a
787 Statements do not return values. Therefore, you can’t assign a `let` statement
788 to another variable, as the following code tries to do; you’ll get an error:
790 Filename: src/main.rs
798 When you run this program, the error you’ll get looks like this:
802 Compiling functions v0.1.0 (file:///projects/functions)
803 error: expected expression, found statement (`let`)
806 2 | let x = (let y = 6);
809 = note: variable declaration using `let` is a statement
812 The `let y = 6` statement does not return a value, so there isn’t anything for
813 `x` to bind to. This is different from what happens in other languages, such as
814 C and Ruby, where the assignment returns the value of the assignment. In those
815 languages, you can write `x = y = 6` and have both `x` and `y` have the value
816 `6`; that is not the case in Rust.
818 Expressions evaluate to something and make up most of the rest of the code that
819 you’ll write in Rust. Consider a simple math operation, such as `5 + 6`, which
820 is an expression that evaluates to the value `11`. Expressions can be part of
821 statements: in Listing 3-1, the `6` in the statement `let y = 6;` is an
822 expression that evaluates to the value `6`. Calling a function is an
823 expression. Calling a macro is an expression. The block that we use to create
824 new scopes, `{}`, is an expression, for example:
826 Filename: src/main.rs
837 println!("The value of y is: {}", y);
850 is a block that, in this case, evaluates to `4`. That value gets bound to `y`
851 as part of the `let` statement. Note the `x + 1` line without a semicolon at
852 the end, which is unlike most of the lines you’ve seen so far. Expressions do
853 not include ending semicolons. If you add a semicolon to the end of an
854 expression, you turn it into a statement, which will then not return a value.
855 Keep this in mind as you explore function return values and expressions next.
857 ### Functions with Return Values
859 Functions can return values to the code that calls them. We don’t name return
860 values, but we do declare their type after an arrow (`->`). In Rust, the return
861 value of the function is synonymous with the value of the final expression in
862 the block of the body of a function. You can return early from a function by
863 using the `return` keyword and specifying a value, but most functions return
864 the last expression implicitly. Here’s an example of a function that returns a
867 Filename: src/main.rs
877 println!("The value of x is: {}", x);
881 There are no function calls, macros, or even `let` statements in the `five`
882 function—just the number `5` by itself. That’s a perfectly valid function in
883 Rust. Note that the function’s return type is specified, too, as `-> i32`. Try
884 running this code; the output should look like this:
888 Compiling functions v0.1.0 (file:///projects/functions)
889 Finished dev [unoptimized + debuginfo] target(s) in 0.30 secs
890 Running `target/debug/functions`
894 The `5` in `five` is the function’s return value, which is why the return type
895 is `i32`. Let’s examine this in more detail. There are two important bits:
896 first, the line `let x = five();` shows that we’re using the return value of a
897 function to initialize a variable. Because the function `five` returns a `5`,
898 that line is the same as the following:
904 Second, the `five` function has no parameters and defines the type of the
905 return value, but the body of the function is a lonely `5` with no semicolon
906 because it’s an expression whose value we want to return.
908 Let’s look at another example:
910 Filename: src/main.rs
916 println!("The value of x is: {}", x);
919 fn plus_one(x: i32) -> i32 {
924 Running this code will print `The value of x is: 6`. But if we place a
925 semicolon at the end of the line containing `x + 1`, changing it from an
926 expression to a statement, we’ll get an error.
928 Filename: src/main.rs
934 println!("The value of x is: {}", x);
937 fn plus_one(x: i32) -> i32 {
942 Running this code produces an error, as follows:
945 error[E0308]: mismatched types
948 7 | fn plus_one(x: i32) -> i32 {
949 | ____________________________^
951 | | - help: consider removing this semicolon
953 | |_^ expected i32, found ()
955 = note: expected type `i32`
959 The main error message, “mismatched types,” reveals the core issue with this
960 code. The definition of the function `plus_one` says that it will return an
961 `i32`, but statements don’t evaluate to a value, which is expressed by `()`,
962 the empty tuple. Therefore, nothing is returned, which contradicts the function
963 definition and results in an error. In this output, Rust provides a message to
964 possibly help rectify this issue: it suggests removing the semicolon, which
969 All programmers strive to make their code easy to understand, but sometimes
970 extra explanation is warranted. In these cases, programmers leave notes, or
971 *comments*, in their source code that the compiler will ignore but people
972 reading the source code may find useful.
974 Here’s a simple comment:
980 In Rust, comments must start with two slashes and continue until the end of the
981 line. For comments that extend beyond a single line, you’ll need to include
982 `//` on each line, like this:
985 // So we’re doing something complicated here, long enough that we need
986 // multiple lines of comments to do it! Whew! Hopefully, this comment will
987 // explain what’s going on.
990 Comments can also be placed at the end of lines containing code:
992 Filename: src/main.rs
996 let lucky_number = 7; // I’m feeling lucky today.
1000 But you’ll more often see them used in this format, with the comment on a
1001 separate line above the code it’s annotating:
1003 Filename: src/main.rs
1007 // I’m feeling lucky today.
1008 let lucky_number = 7;
1012 Rust also has another kind of comment, documentation comments, which we’ll
1013 discuss in Chapter 14.
1017 Deciding whether or not to run some code depending on if a condition is true
1018 and deciding to run some code repeatedly while a condition is true are basic
1019 building blocks in most programming languages. The most common constructs that
1020 let you control the flow of execution of Rust code are `if` expressions and
1023 ### `if` Expressions
1025 An `if` expression allows you to branch your code depending on conditions. You
1026 provide a condition and then state, “If this condition is met, run this block
1027 of code. If the condition is not met, do not run this block of code.”
1029 Create a new project called *branches* in your *projects* directory to explore
1030 the `if` expression. In the *src/main.rs* file, input the following:
1032 Filename: src/main.rs
1039 println!("condition was true");
1041 println!("condition was false");
1046 <!-- NEXT PARAGRAPH WRAPPED WEIRD INTENTIONALLY SEE #199 -->
1048 All `if` expressions start with the keyword `if`, which is followed by a
1049 condition. In this case, the condition checks whether or not the variable
1050 `number` has a value less than 5. The block of code we want to execute if the
1051 condition is true is placed immediately after the condition inside curly
1052 brackets. Blocks of code associated with the conditions in `if` expressions are
1053 sometimes called *arms*, just like the arms in `match` expressions that we
1054 discussed in the “Comparing the Guess to the Secret Number” section of
1057 Optionally, we can also include an `else` expression, which we chose
1058 to do here, to give the program an alternative block of code to execute should
1059 the condition evaluate to false. If you don’t provide an `else` expression and
1060 the condition is false, the program will just skip the `if` block and move on
1061 to the next bit of code.
1063 Try running this code; you should see the following output:
1067 Compiling branches v0.1.0 (file:///projects/branches)
1068 Finished dev [unoptimized + debuginfo] target(s) in 0.31 secs
1069 Running `target/debug/branches`
1073 Let’s try changing the value of `number` to a value that makes the condition
1074 `false` to see what happens:
1080 Run the program again, and look at the output:
1084 Compiling branches v0.1.0 (file:///projects/branches)
1085 Finished dev [unoptimized + debuginfo] target(s) in 0.31 secs
1086 Running `target/debug/branches`
1090 It’s also worth noting that the condition in this code *must* be a `bool`. If
1091 the condition isn’t a `bool`, we’ll get an error. For example:
1093 Filename: src/main.rs
1100 println!("number was three");
1105 The `if` condition evaluates to a value of `3` this time, and Rust throws an
1109 error[E0308]: mismatched types
1113 | ^^^^^^ expected bool, found integral variable
1115 = note: expected type `bool`
1116 found type `{integer}`
1119 The error indicates that Rust expected a `bool` but got an integer. Unlike
1120 languages such as Ruby and JavaScript, Rust will not automatically try to
1121 convert non-Boolean types to a Boolean. You must be explicit and always provide
1122 `if` with a Boolean as its condition. If we want the `if` code block to run
1123 only when a number is not equal to `0`, for example, we can change the `if`
1124 expression to the following:
1126 Filename: src/main.rs
1133 println!("number was something other than zero");
1138 Running this code will print `number was something other than zero`.
1140 #### Handling Multiple Conditions with `else if`
1142 You can have multiple conditions by combining `if` and `else` in an `else if`
1143 expression. For example:
1145 Filename: src/main.rs
1151 if number % 4 == 0 {
1152 println!("number is divisible by 4");
1153 } else if number % 3 == 0 {
1154 println!("number is divisible by 3");
1155 } else if number % 2 == 0 {
1156 println!("number is divisible by 2");
1158 println!("number is not divisible by 4, 3, or 2");
1163 This program has four possible paths it can take. After running it, you should
1164 see the following output:
1168 Compiling branches v0.1.0 (file:///projects/branches)
1169 Finished dev [unoptimized + debuginfo] target(s) in 0.31 secs
1170 Running `target/debug/branches`
1171 number is divisible by 3
1174 When this program executes, it checks each `if` expression in turn and executes
1175 the first body for which the condition holds true. Note that even though 6 is
1176 divisible by 2, we don’t see the output `number is divisible by 2`, nor do we
1177 see the `number is not divisible by 4, 3, or 2` text from the `else` block.
1178 That’s because Rust only executes the block for the first true condition, and
1179 once it finds one, it doesn’t even check the rest.
1181 Using too many `else if` expressions can clutter your code, so if you have more
1182 than one, you might want to refactor your code. Chapter 6 describes a powerful
1183 Rust branching construct called `match` for these cases.
1185 #### Using `if` in a `let` Statement
1187 Because `if` is an expression, we can use it on the right side of a `let`
1188 statement, as in Listing 3-2:
1190 Filename: src/main.rs
1194 let condition = true;
1195 let number = if condition {
1201 println!("The value of number is: {}", number);
1205 Listing 3-2: Assigning the result of an `if` expression to a variable
1207 The `number` variable will be bound to a value based on the outcome of the `if`
1208 expression. Run this code to see what happens:
1212 Compiling branches v0.1.0 (file:///projects/branches)
1213 Finished dev [unoptimized + debuginfo] target(s) in 0.30 secs
1214 Running `target/debug/branches`
1215 The value of number is: 5
1218 Remember that blocks of code evaluate to the last expression in them, and
1219 numbers by themselves are also expressions. In this case, the value of the
1220 whole `if` expression depends on which block of code executes. This means the
1221 values that have the potential to be results from each arm of the `if` must be
1222 the same type; in Listing 3-2, the results of both the `if` arm and the `else`
1223 arm were `i32` integers. If the types are mismatched, as in the following
1224 example, we’ll get an error:
1226 Filename: src/main.rs
1230 let condition = true;
1232 let number = if condition {
1238 println!("The value of number is: {}", number);
1242 When we try to run this code, we’ll get an error. The `if` and `else` arms have
1243 value types that are incompatible, and Rust indicates exactly where to find the
1244 problem in the program:
1247 error[E0308]: if and else have incompatible types
1248 --> src/main.rs:4:18
1250 4 | let number = if condition {
1251 | __________________^
1256 | |_____^ expected integral variable, found &str
1258 = note: expected type `{integer}`
1262 The expression in the `if` block evaluates to an integer, and the expression in
1263 the `else` block evaluates to a string. This won’t work because variables must
1264 have a single type. Rust needs to know at compile time what type the `number`
1265 variable is, definitively, so it can verify at compile time that its type is
1266 valid everywhere we use `number`. Rust wouldn’t be able to do that if the type
1267 of `number` was only determined at runtime; the compiler would be more complex
1268 and would make fewer guarantees about the code if it had to keep track of
1269 multiple hypothetical types for any variable.
1271 ### Repetition with Loops
1273 It’s often useful to execute a block of code more than once. For this task,
1274 Rust provides several *loops*. A loop runs through the code inside the loop
1275 body to the end and then starts immediately back at the beginning. To
1276 experiment with loops, let’s make a new project called *loops*.
1278 Rust has three kinds of loops: `loop`, `while`, and `for`. Let’s try each one.
1280 #### Repeating Code with `loop`
1282 The `loop` keyword tells Rust to execute a block of code over and over again
1283 forever or until you explicitly tell it to stop.
1285 As an example, change the *src/main.rs* file in your *loops* directory to look
1288 Filename: src/main.rs
1298 When we run this program, we’ll see `again!` printed over and over continuously
1299 until we stop the program manually. Most terminals support a keyboard shortcut,
1300 <span class="keystroke">ctrl-c</span>, to halt a program that is stuck in a
1301 continual loop. Give it a try:
1305 Compiling loops v0.1.0 (file:///projects/loops)
1306 Finished dev [unoptimized + debuginfo] target(s) in 0.29 secs
1307 Running `target/debug/loops`
1315 The symbol `^C` represents where you pressed <span class="keystroke">ctrl-c
1316 </span>. You may or may not see the word `again!` printed after the `^C`,
1317 depending on where the code was in the loop when it received the halt signal.
1319 Fortunately, Rust provides another, more reliable way to break out of a loop.
1320 You can place the `break` keyword within the loop to tell the program when to
1321 stop executing the loop. Recall that we did this in the guessing game in the
1322 “Quitting After a Correct Guess” section of Chapter 2 to exit the
1323 program when the user won the game by guessing the correct number.
1325 #### Conditional Loops with `while`
1327 It’s often useful for a program to evaluate a condition within a loop. While
1328 the condition is true, the loop runs. When the condition ceases to be true, the
1329 program calls `break`, stopping the loop. This loop type could be implemented
1330 using a combination of `loop`, `if`, `else`, and `break`; you could try that
1331 now in a program, if you’d like.
1333 However, this pattern is so common that Rust has a built-in language construct
1334 for it, called a `while` loop. Listing 3-3 uses `while`: the program loops
1335 three times, counting down each time, and then, after the loop, it prints
1336 another message and exits.
1338 Filename: src/main.rs
1345 println!("{}!", number);
1347 number = number - 1;
1350 println!("LIFTOFF!!!");
1354 Listing 3-3: Using a `while` loop to run code while a condition holds true
1356 This construct eliminates a lot of nesting that would be necessary if you used
1357 `loop`, `if`, `else`, and `break`, and it’s clearer. While a condition holds
1358 true, the code runs; otherwise, it exits the loop.
1360 #### Looping Through a Collection with `for`
1362 You could use the `while` construct to loop over the elements of a collection,
1363 such as an array. For example, let’s look at Listing 3-4:
1365 Filename: src/main.rs
1369 let a = [10, 20, 30, 40, 50];
1373 println!("the value is: {}", a[index]);
1380 Listing 3-4: Looping through each element of a collection using a `while` loop
1382 Here, the code counts up through the elements in the array. It starts at index
1383 `0`, and then loops until it reaches the final index in the array (that is,
1384 when `index < 5` is no longer true). Running this code will print every element
1389 Compiling loops v0.1.0 (file:///projects/loops)
1390 Finished dev [unoptimized + debuginfo] target(s) in 0.32 secs
1391 Running `target/debug/loops`
1399 All five array values appear in the terminal, as expected. Even though `index`
1400 will reach a value of `5` at some point, the loop stops executing before trying
1401 to fetch a sixth value from the array.
1403 But this approach is error prone; we could cause the program to panic if the
1404 index length is incorrect. It’s also slow, because the compiler adds runtime
1405 code to perform the conditional check on every element on every iteration
1408 As a more concise alternative, you can use a `for` loop and execute some code
1409 for each item in a collection. A `for` loop looks like this code in Listing 3-5:
1411 Filename: src/main.rs
1415 let a = [10, 20, 30, 40, 50];
1417 for element in a.iter() {
1418 println!("the value is: {}", element);
1423 Listing 3-5: Looping through each element of a collection using a `for` loop
1425 When we run this code, we’ll see the same output as in Listing 3-4. More
1426 importantly, we’ve now increased the safety of the code and eliminated the
1427 chance of bugs that might result from going beyond the end of the array or not
1428 going far enough and missing some items.
1430 For example, in the code in Listing 3-4, if you removed an item from the `a`
1431 array but forgot to update the condition to `while index < 4`, the code would
1432 panic. Using the `for` loop, you wouldn’t need to remember to change any other
1433 code if you changed the number of values in the array.
1435 The safety and conciseness of `for` loops make them the most commonly used loop
1436 construct in Rust. Even in situations in which you want to run some code a
1437 certain number of times, as in the countdown example that used a `while` loop
1438 in Listing 3-3, most Rustaceans would use a `for` loop. The way to do that
1439 would be to use a `Range`, which is a type provided by the standard library
1440 that generates all numbers in sequence starting from one number and ending
1441 before another number.
1443 Here’s what the countdown would look like using a `for` loop and another method
1444 we’ve not yet talked about, `rev`, to reverse the range:
1446 Filename: src/main.rs
1450 for number in (1..4).rev() {
1451 println!("{}!", number);
1453 println!("LIFTOFF!!!");
1457 This code is a bit nicer, isn’t it?
1461 You made it! That was a sizable chapter: you learned about variables, scalar
1462 and compound data types, functions, comments, `if` expressions, and loops! If
1463 you want to practice with the concepts discussed in this chapter, try building
1464 programs to do the following:
1466 * Convert temperatures between Fahrenheit and Celsius.
1467 * Generate the nth Fibonacci number.
1468 * Print the lyrics to the Christmas carol “The Twelve Days of Christmas,”
1469 taking advantage of the repetition in the song.
1471 When you’re ready to move on, we’ll talk about a concept in Rust that *doesn’t*
1472 commonly exist in other programming languages: ownership.