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 their conventions.
11 Specifically, you’ll learn about variables, basic types, functions, comments,
12 and control flow. These foundations will be in every Rust program, and learning
13 them early will give you a strong core to start from.
19 The Rust language has a set of *keywords* that have been reserved for use by
20 the language only, much like other languages do. Keep in mind that you cannot
21 use these words as names of variables or functions. Most of the keywords have
22 special meanings, and you’ll be using them to do various tasks in your Rust
23 programs; a few have no current functionality associated with them but have
24 been reserved for functionality that might be added to Rust in the future. You
25 can find a list of the keywords in Appendix A.
29 ## Variables and Mutability
31 As mentioned in Chapter 2, by default variables are *immutable*. This is one of
32 many nudges in Rust that encourages you to write your code in a way that takes
33 advantage of the safety and easy concurrency that Rust offers. However, you
34 still have the option to make your variables mutable. Let’s explore how and why
35 Rust encourages you to favor immutability, and why you might want to opt out.
37 When a variable is immutable, that means once a value is bound to a name, you
38 can’t change that value. To illustrate, let’s generate a new project called
39 *variables* in your *projects* directory by using `cargo new --bin variables`.
41 Then, in your new *variables* directory, open *src/main.rs* and replace its
42 code with the following:
49 println!("The value of x is: {}", x);
51 println!("The value of x is: {}", x);
55 Save and run the program using `cargo run`. You should receive an error
56 message, as shown in this output:
59 error[E0384]: re-assignment of immutable variable `x`
63 | - first assignment to `x`
64 3 | println!("The value of x is: {}", x);
66 | ^^^^^ re-assignment of immutable variable
69 This example shows how the compiler helps you find errors in your programs.
70 Even though compiler errors can be frustrating, they only mean your program
71 isn’t safely doing what you want it to do yet; they do *not* mean that you’re
72 not a good programmer! Experienced Rustaceans still get compiler errors. The
73 error indicates that the cause of the error is `re-assignment of immutable
74 variable`, because we tried to assign a second value to the immutable `x`
77 It’s important that we get compile-time errors when we attempt to change a
78 value that we previously designated as immutable because this very situation
79 can lead to bugs. If one part of our code operates on the assumption that a
80 value will never change and another part of our code changes that value, it’s
81 possible that the first part of the code won’t do what it was designed to do.
82 This cause of bugs can be difficult to track down after the fact, especially
83 when the second piece of code changes the value only *sometimes*.
85 In Rust the compiler guarantees that when we state that a value won’t change,
86 it really won’t change. That means that when you’re reading and writing code,
87 you don’t have to keep track of how and where a value might change, which can
88 make code easier to reason about.
90 But mutability can be very useful. Variables are immutable only by default; we
91 can make them mutable by adding `mut` in front of the variable name. In
92 addition to allowing this value to change, it conveys intent to future readers
93 of the code by indicating that other parts of the code will be changing this
96 For example, change *src/main.rs* to the following:
103 println!("The value of x is: {}", x);
105 println!("The value of x is: {}", x);
109 When we run this program, we get the following:
113 Compiling variables v0.1.0 (file:///projects/variables)
114 Running `target/debug/variables`
119 Using `mut`, we’re allowed to change the value that `x` binds to from `5` to
120 `6`. In some cases, you’ll want to make a variable mutable because it makes the
121 code more convenient to write than an implementation that only uses immutable
124 There are multiple trade-offs to consider, in addition to the prevention of
125 bugs. For example, in cases where you’re using large data structures, mutating
126 an instance in place may be faster than copying and returning newly allocated
127 instances. With smaller data structures, creating new instances and writing in
128 a more functional programming style may be easier to reason about, so the lower
129 performance might be a worthwhile penalty for gaining that clarity.
131 ### Differences Between Variables and Constants
133 Being unable to change the value of a variable might have reminded you of
134 another programming concept that most other languages have: *constants*. Like
135 immutable variables, constants are also values that are bound to a name and
136 are not allowed to change, but there are a few differences between constants
139 First, we aren’t allowed to use `mut` with constants: constants aren't only
140 immutable by default, they're always immutable.
142 We declare constants using the `const` keyword instead of the `let` keyword,
143 and the type of the value *must* be annotated. We're about to cover types and
144 type annotations in the next section, “Data Types,” so don't worry about the
145 details right now, just know that we must always annotate the type.
147 Constants can be declared in any scope, including the global scope, which makes
148 them useful for values that many parts of code need to know about.
150 The last difference is that constants may only be set to a constant expression,
151 not the result of a function call or any other value that could only be
154 Here's an example of a constant declaration where the constant's name is
155 `MAX_POINTS` and its value is set to 100,000. (Rust constant naming convention
156 is to use all upper case with underscores between words):
159 const MAX_POINTS: u32 = 100_000;
162 Constants are valid for the entire time a program runs, within the scope they
163 were declared in, making them a useful choice for values in your application
164 domain that multiple part of the program might need to know about, such as the
165 maximum number of points any player of a game is allowed to earn or the speed
168 Naming hardcoded values used throughout your program as constants is useful in
169 conveying the meaning of that value to future maintainers of the code. It also
170 helps to have only one place in your code you would need to change if the
171 hardcoded value needed to be updated in the future.
175 As we saw in the guessing game tutorial in Chapter 2, we can declare new
176 variables with the same name as a previous variables, and the new variable
177 *shadows* the previous variable. Rustaceans say that the first variable is
178 *shadowed* by the second, which means that the second variable’s value is what
179 we’ll see when we use the variable. We can shadow a variable by using the same
180 variable’s name and repeating the use of the `let` keyword as follows:
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`, taking the
199 previous value and multiplying it by `2` to give `x` a final value of `12`.
200 When you run this program, it will output the following:
204 Compiling variables v0.1.0 (file:///projects/variables)
205 Running `target/debug/variables`
206 The value of x is: 12
209 This is different than marking a variable as `mut`, because unless we use the
210 `let` keyword again, we’ll get a compile-time error if we accidentally try to
211 reassign to this variable. We can perform a few transformations on a value but
212 have the variable be immutable after those transformations have been completed.
214 The other difference between `mut` and shadowing is that because we’re
215 effectively creating a new variable when we use the `let` keyword again, we can
216 change the type of the value, but reuse the same name. For example, say our
217 program asks a user to show how many spaces they want between some text by
218 inputting space characters, but we really want to store that input as a number:
222 let spaces = spaces.len();
225 This construct is allowed because the first `spaces` variable is a string type,
226 and the second `spaces` variable, which is a brand-new variable that happens to
227 have the same name as the first one, is a number type. Shadowing thus spares us
228 from having to come up with different names, like `spaces_str` and
229 `spaces_num`; instead, we can reuse the simpler `spaces` name. However, if we
230 try to use `mut` for this, as shown here:
233 let mut spaces = " ";
234 spaces = spaces.len();
237 we’ll get a compile-time error because we’re not allowed to mutate a variable’s
241 error[E0308]: mismatched types
244 3 | spaces = spaces.len();
245 | ^^^^^^^^^^^^ expected &str, found usize
247 = note: expected type `&str`
251 Now that we’ve explored how variables work, let’s look at more data types they
256 Every value in Rust is of a certain *type*, which tells Rust what kind of data
257 is being specified so it knows how to work with that data. In this section,
258 we’ll look at a number of types that are built into the language. We split the
259 types into two subsets: scalar and compound.
261 Throughout this section, keep in mind that Rust is a *statically typed*
262 language, which means that it must know the types of all variables at compile
263 time. The compiler can usually infer what type we want to use based on the
264 value and how we use it. In cases when many types are possible, such as when we
265 converted a `String` to a numeric type using `parse` in Chapter 2, we must add
266 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
274 possible type we want to use:
277 error[E0282]: unable to infer enough type information about `_`
280 2 | let guess = "42".parse().expect("Not a number!");
281 | ^^^^^ cannot infer type for `_`
283 = note: type annotations or generic parameter binding required
286 You’ll see different type annotations as we discuss the various data types.
290 A *scalar* type represents a single value. Rust has four primary scalar types:
291 integers, floating-point numbers, booleans, and characters. You’ll likely
292 recognize these from other programming languages, but let’s jump into how they
297 An *integer* is a number without a fractional component. We used one integer
298 type earlier in this chapter, the `i32` type. This type declaration indicates
299 that the value it’s associated with should be a signed integer (hence the `i`,
300 as opposed to a `u` for unsigned) that takes up 32 bits of space. Table 3-1
301 shows the built-in integer types in Rust. Each variant in the Signed and
302 Unsigned columns (for example, *i32*) can be used to declare the type of an
306 Table 3-1: Integer Types in Rust
309 | Length | Signed | Unsigned |
310 |--------|--------|----------|
312 | 16-bit | i16 | u16 |
313 | 32-bit | i32 | u32 |
314 | 64-bit | i64 | u64 |
315 | arch | isize | usize |
317 Each variant can be either signed or unsigned and has an explicit size.
318 Signed and unsigned refers to whether it’s possible for the number to be
319 negative or positive; in other words, whether the number needs to have a sign
320 with it (signed) or whether it will only ever be positive and can therefore be
321 represented without a sign (unsigned). It’s like writing numbers on paper: when
322 the sign matters, a number is shown with a plus sign or a minus sign; however,
323 when it’s safe to assume the number is positive, it’s shown with no sign.
324 Signed numbers are stored using two’s complement representation (if you’re
325 unsure what this is, you can search for it online; an explanation is outside
326 the scope of this book).
328 Each signed variant can store numbers from -2<sup>n - 1</sup> to 2<sup>n - 1</sup> - 1 inclusive,
329 where `n` is the number of bits that variant uses. So an `i8` can store numbers
330 from -2<sup>7</sup> to 2<sup>7</sup> - 1, which equals -128 to 127. Unsigned variants can store
331 numbers from 0 to 2<sup>n</sup> - 1, so a `u8` can store numbers from 0 to 2<sup>8</sup> - 1, which
334 Additionally, the `isize` and `usize` types depend on the kind of computer your
335 program is running on: 64-bits if you’re on a 64-bit architecture and 32-bits
336 if you’re on a 32-bit architecture.
338 You can write integer literals in any of the forms shown in Table 3-2. Note
339 that all number literals except the byte literal allow a type suffix, such as
340 `57u8`, and `_` as a visual separator, such as `1_000`.
343 Table 3-2: Integer Literals in Rust
346 | Number literals | Example |
347 |------------------|---------------|
348 | Decimal | `98_222` |
351 | Binary | `0b1111_0000` |
352 | Byte (`u8` only) | `b'A'` |
354 So how do you know which type of integer to use? If you’re unsure, Rust’s
355 defaults are generally good choices, and integer types default to `i32`: it’s
356 generally the fastest, even on 64-bit systems. The primary situation in which
357 you’d use `isize` or `usize` is when indexing some sort of collection.
359 #### Floating-Point Types
361 Rust also has two primitive types for *floating-point numbers*, which are
362 numbers with decimal points. Rust’s floating-point types are `f32` and `f64`,
363 which are 32 bits and 64 bits in size, respectively. The default type is `f64`
364 because it’s roughly the same speed as `f32` but is capable of more precision.
365 It’s possible to use an `f64` type on 32-bit systems, but it will be slower
366 than using an `f32` type on those systems. Most of the time, trading potential
367 worse performance for better precision is a reasonable initial choice, and you
368 should benchmark your code if you suspect floating-point size is a problem in
371 Here’s an example that shows floating-point numbers in action:
373 Filename: src/main.rs
379 let y: f32 = 3.0; // f32
383 Floating-point numbers are represented according to the IEEE-754 standard. The
384 `f32` type is a single-precision float, and `f64` has double precision.
386 #### Numeric Operations
388 Rust supports the usual basic mathematic operations you’d expect for all of the
389 number types: addition, subtraction, multiplication, division, and remainder.
390 The following code shows how you’d use each one in a `let` statement:
392 Filename: src/main.rs
400 let difference = 95.5 - 4.3;
403 let product = 4 * 30;
406 let quotient = 56.7 / 32.2;
409 let remainder = 43 % 5;
413 Each expression in these statements uses a mathematical operator and evaluates
414 to a single value, which is then bound to a variable. Appendix B contains a
415 list of all operators that Rust provides.
417 #### The Boolean Type
419 As in most other programming languages, a boolean type in Rust has two possible
420 values: `true` and `false`. The boolean type in Rust is specified using `bool`.
423 Filename: src/main.rs
429 let f: bool = false; // with explicit type annotation
433 The main way to consume boolean values is through conditionals, such as an `if`
434 statement. We’ll cover how `if` statements work in Rust in the “Control Flow”
437 #### The Character Type
439 So far we’ve only worked with numbers, but Rust supports letters too. Rust’s
440 `char` type is the language’s most primitive alphabetic type, and the following
441 code shows one way to use it:
443 Filename: src/main.rs
449 let heart_eyed_cat = '😻';
453 Rust’s `char` type represents a Unicode Scalar Value, which means it can
454 represent a lot more than just ASCII. Accented letters, Chinese/Japanese/Korean
455 ideographs, emoji, and zero width spaces are all valid `char` types in Rust.
456 Unicode Scalar Values range from `U+0000` to `U+D7FF` and `U+E000` to
457 `U+10FFFF` inclusive. However, a “character” isn’t really a concept in Unicode,
458 so your human intuition for what a “character” is may not match up with what a
459 `char` is in Rust. We’ll discuss this topic in detail in the “Strings” section
464 *Compound types* can group multiple values of other types into one type. Rust
465 has two primitive compound types: tuples and arrays.
467 #### Grouping Values into Tuples
469 A tuple is a general way of grouping together some number of other values with
470 a variety of types into one compound type.
472 We create a tuple by writing a comma-separated list of values inside
473 parentheses. Each position in the tuple has a type, and the types of the
474 different values in the tuple don’t have to be the same. We’ve added optional
475 type annotations in this example:
477 Filename: src/main.rs
481 let tup: (i32, f64, u8) = (500, 6.4, 1);
485 The variable `tup` binds to the entire tuple, since a tuple is considered a
486 single compound element. To get the individual values out of a tuple, we can
487 use pattern matching to destructure a tuple value, like this:
489 Filename: src/main.rs
493 let tup = (500, 6.4, 1);
497 println!("The value of y is: {}", y);
501 This program first creates a tuple and binds it to the variable `tup`. It then
502 uses a pattern with `let` to take `tup` and turn it into three separate
503 variables, `x`, `y`, and `z`. This is called *destructuring*, because it breaks
504 the single tuple into three parts. Finally, the program prints the value of
507 In addition to destructuring through pattern matching, we can also access a
508 tuple element directly by using a period (`.`) followed by the index of the
509 value we want to access. For example:
511 Filename: src/main.rs
515 let x: (i32, f64, u8) = (500, 6.4, 1);
517 let five_hundred = x.0;
519 let six_point_four = x.1;
525 This program creates a tuple, `x`, and then makes new variables for each
526 element by using their index. As with most programming languages, the first
527 index in a tuple is 0.
531 Another way to have a collection of multiple values is with an *array*. Unlike
532 a tuple, every element of an array must have the same type. Arrays in Rust are
533 different than arrays in some other languages because arrays in Rust have a
534 fixed length: once declared, they cannot grow or shrink in size.
536 In Rust, the values going into an array are written as a comma-separated list
537 inside square brackets:
539 Filename: src/main.rs
543 let a = [1, 2, 3, 4, 5];
547 Arrays are useful when you want your data allocated on the stack rather than
548 the heap (we will discuss the stack and the heap more in Chapter 4), or when
549 you want to ensure you always have a fixed number of elements. They aren’t as
550 flexible as the vector type, though. The vector type is a similar collection
551 type provided by the standard library that *is* allowed to grow or shrink in
552 size. If you’re unsure whether to use an array or a vector, you should probably
553 use a vector: Chapter 8 discusses vectors in more detail.
555 An example of when you might want to use an array rather than a vector is in a
556 program that needs to know the names of the months of the year. It’s very
557 unlikely that such a program will need to add or remove months, so you can use
558 an array because you know it will always contain 12 items:
561 let months = ["January", "February", "March", "April", "May", "June", "July",
562 "August", "September", "October", "November", "December"];
565 ##### Accessing Array Elements
567 An array is a single chunk of memory allocated on the stack. We can access
568 elements of an array using indexing, like this:
570 Filename: src/main.rs
574 let a = [1, 2, 3, 4, 5];
581 In this example, the variable named `first` will get the value `1`, because
582 that is the value at index `[0]` in the array. The variable named `second` will
583 get the value `2` from index `[1]` in the array.
585 ##### Invalid Array Element Access
587 What happens if we try to access an element of an array that is past the end of
588 the array? Say we change the example to the following:
590 Filename: src/main.rs
594 let a = [1, 2, 3, 4, 5];
597 let element = a[index];
599 println!("The value of element is: {}", element);
603 Running this code using `cargo run` produces the following result:
607 Compiling arrays v0.1.0 (file:///projects/arrays)
608 Running `target/debug/arrays`
609 thread '<main>' panicked at 'index out of bounds: the len is 5 but the index is
611 note: Run with `RUST_BACKTRACE=1` for a backtrace.
614 The compilation didn’t produce any errors, but the program results in a
615 *runtime* error and didn’t exit successfully. When you attempt to access an
616 element using indexing, Rust will check that the index you’ve specified is less
617 than the array length. If the index is greater than the length, Rust will
618 *panic*, which is the term Rust uses when a program exits with an error.
620 This is the first example of Rust’s safety principles in action. In many
621 low-level languages, this kind of check is not done, and when you provide an
622 incorrect index, invalid memory can be accessed. Rust protects you against this
623 kind of error by immediately exiting instead of allowing the memory access and
624 continuing. Chapter 9 discusses more of Rust’s error handling.
626 ## How Functions Work
628 Functions are pervasive in Rust code. You’ve already seen one of the most
629 important functions in the language: the `main` function, which is the entry
630 point of many programs. You’ve also seen the `fn` keyword, which allows you to
631 declare new functions.
633 Rust code uses *snake case* as the conventional style for function and variable
634 names. In snake case, all letters are lowercase and underscores separate words.
635 Here’s a program that contains an example function definition:
637 Filename: src/main.rs
641 println!("Hello, world!");
646 fn another_function() {
647 println!("Another function.");
651 Function definitions in Rust start with `fn` and have a set of parentheses
652 after the function name. The curly braces tell the compiler where the function
653 body begins and ends.
655 We can call any function we’ve defined by entering its name followed by a set
656 of parentheses. Because `another_function` is defined in the program, it can be
657 called from inside the `main` function. Note that we defined `another_function`
658 *after* the `main` function in the source code; we could have defined it before
659 as well. Rust doesn’t care where you define your functions, only that they’re
662 Let’s start a new binary project named *functions* to explore functions
663 further. Place the `another_function` example in *src/main.rs* and run it. You
664 should see the following output:
668 Compiling functions v0.1.0 (file:///projects/functions)
669 Running `target/debug/functions`
674 The lines execute in the order in which they appear in the `main` function.
675 First, the “Hello, world!” message prints, and then `another_function` is
676 called and its message is printed.
678 ### Function Parameters
680 Functions can also be defined to have *parameters*, which are special variables
681 that are part of a function's signature. When a function has parameters, we can
682 provide it with concrete values for those parameters. Technically, the concrete
683 values are called *arguments*, but in casual conversation people tend to use
684 the words “parameter” and “argument” interchangeably for either the variables
685 in a function's definition or the concrete values passed in when you call a
688 The following rewritten version of `another_function` shows what parameters
691 Filename: src/main.rs
698 fn another_function(x: i32) {
699 println!("The value of x is: {}", x);
703 Try running this program; you should get the following output:
707 Compiling functions v0.1.0 (file:///projects/functions)
708 Running `target/debug/functions`
712 The declaration of `another_function` has one parameter named `x`. The type of
713 `x` is specified as `i32`. When `5` is passed to `another_function`, the
714 `println!` macro puts `5` where the pair of curly braces were in the format
717 In function signatures, you *must* declare the type of each parameter. This is
718 a deliberate decision in Rust’s design: requiring type annotations in function
719 definitions means the compiler almost never needs you to use them elsewhere in
720 the code to figure out what you mean.
722 When you want a function to have multiple parameters, separate the parameter
723 declarations with commas, like this:
725 Filename: src/main.rs
729 another_function(5, 6);
732 fn another_function(x: i32, y: i32) {
733 println!("The value of x is: {}", x);
734 println!("The value of y is: {}", y);
738 This example creates a function with two parameters, both of which are `i32`
739 types. The function then prints out the values in both of its parameters. Note
740 that function parameters don't all need to be the same type, they just happen
741 to be in this example.
743 Let’s try running this code. Replace the program currently in your *function*
744 project’s *src/main.rs* file with the preceding example, and run it using
749 Compiling functions v0.1.0 (file:///projects/functions)
750 Running `target/debug/functions`
755 Because we called the function with `5` as the value for `x` and `6` is passed
756 as the value for `y`, the two strings are printed with these values.
760 Function bodies are made up of a series of statements optionally ending in an
761 expression. So far, we’ve only covered functions without an ending expression,
762 but we have seen expressions as parts of statements. Because Rust is an
763 expression-based language, this is an important distinction to understand.
764 Other languages don’t have the same distinctions, so let’s look at what
765 statements and expressions are and how their differences affect the bodies of
768 ### Statements and Expressions
770 We’ve actually already used statements and expressions. *Statements* are
771 instructions that perform some action and do not return a value. *Expressions*
772 evaluate to a resulting value. Let’s look at some examples.
774 Creating a variable and assigning a value to it with the `let` keyword is a
775 statement. In Listing 3-3, `let y = 6;` is a statement:
777 Filename: src/main.rs
786 Listing 3-3: A `main` function declaration containing one statement.
789 Function definitions are also statements; the entire preceding example is a
792 Statements do not return values. Therefore, you can’t assign a `let` statement
793 to another variable, as the following code tries to do:
795 Filename: src/main.rs
803 When you run this program, you’ll get an error like this:
807 Compiling functions v0.1.0 (file:///projects/functions)
808 error: expected expression, found statement (`let`)
811 2 | let x = (let y = 6);
814 = note: variable declaration using `let` is a statement
817 The `let y = 6` statement does not return a value, so there isn’t anything for
818 `x` to bind to. This is different than in other languages, such as C and Ruby,
819 where the assignment returns the value of the assignment. In those languages,
820 you can write `x = y = 6` and have both `x` and `y` have the value `6`; that is
821 not the case in Rust.
823 Expressions evaluate to something and make up most of the rest of the code that
824 you’ll write in Rust. Consider a simple math operation, such as `5 + 6`, which
825 is an expression that evaluates to the value `11`. Expressions can be part of
826 statements: in Listing 3-3 that had the statement `let y = 6;`, `6` is an
827 expression that evaluates to the value `6`. Calling a function is an
828 expression. Calling a macro is an expression. The block that we use to create
829 new scopes, `{}`, is an expression, for example:
831 Filename: src/main.rs
842 println!("The value of y is: {}", y);
855 is a block that, in this case, evaluates to `4`. That value gets bound to `y`
856 as part of the `let` statement. Note the line without a semicolon at the end,
857 unlike most of the lines you’ve seen so far. Expressions do not include ending
858 semicolons. If you add a semicolon to the end of an expression, you turn it
859 into a statement, which will then not return a value. Keep this in mind as you
860 explore function return values and expressions next.
862 ### Functions with Return Values
864 Functions can return values to the code that calls them. We don’t name return
865 values, but we do declare their type after an arrow (`->`). In Rust, the return
866 value of the function is synonymous with the value of the final expression in
867 the block of the body of a function. Here’s an example of a function that
870 Filename: src/main.rs
880 println!("The value of x is: {}", x);
884 There are no function calls, macros, or even `let` statements in the `five`
885 function—just the number `5` by itself. That’s a perfectly valid function in
886 Rust. Note that the function’s return type is specified, too, as `-> i32`. Try
887 running this code; the output should look like this:
891 Compiling functions v0.1.0 (file:///projects/functions)
892 Running `target/debug/functions`
896 The `5` in `five` is the function’s return value, which is why the return type
897 is `i32`. Let’s examine this in more detail. There are two important bits:
898 first, the line `let x = five();` shows that we’re using the return value of a
899 function to initialize a variable. Because the function `five` returns a `5`,
900 that line is the same as the following:
906 Second, the `five` function has no parameters and defines the type of the
907 return value, but the body of the function is a lonely `5` with no semicolon
908 because it’s an expression whose value we want to return. Let’s look at another
911 Filename: src/main.rs
917 println!("The value of x is: {}", x);
920 fn plus_one(x: i32) -> i32 {
925 Running this code will print `The value of x is: 6`. What happens if we place a
926 semicolon at the end of the line containing `x + 1`, changing it from an
927 expression to a statement?
929 Filename: src/main.rs
935 println!("The value of x is: {}", x);
938 fn plus_one(x: i32) -> i32 {
943 Running this code produces an error, as follows:
946 error[E0308]: mismatched types
949 7 | fn plus_one(x: i32) -> i32 {
950 | ____________________________^ starting here...
953 | |_^ ...ending here: expected i32, found ()
955 = note: expected type `i32`
957 help: consider removing this semicolon:
964 The main error message, “mismatched types,” reveals the core issue with this
965 code. The definition of the function `plus_one` says that it will return an
966 `i32`, but statements don’t evaluate to a value, which is expressed by `()`,
967 the empty tuple. Therefore, nothing is returned, which contradicts the function
968 definition and results in an error. In this output, Rust provides a message to
969 possibly help rectify this issue: it suggests removing the semicolon, which
974 All programmers strive to make their code easy to understand, but sometimes
975 extra explanation is warranted. In these cases, programmers leave notes, or
976 *comments*, in their source code that the compiler will ignore but people
977 reading the source code may find useful.
979 Here’s a simple comment:
985 In Rust, comments must start with two slashes and continue until the end of the
986 line. For comments that extend beyond a single line, you’ll need to include
987 `//` on each line, like this:
990 // So we’re doing something complicated here, long enough that we need
991 // multiple lines of comments to do it! Whew! Hopefully, this comment will
992 // explain what’s going on.
995 Comments can also be placed at the end of lines containing code:
997 Filename: src/main.rs
1001 let lucky_number = 7; // I’m feeling lucky today.
1005 But you’ll more often see them used in this format, with the comment on a
1006 separate line above the code it's annotating:
1008 Filename: src/main.rs
1012 // I’m feeling lucky today.
1013 let lucky_number = 7;
1017 That’s all there is to comments. They’re not particularly complicated.
1021 Deciding whether or not to run some code depending on if a condition is true or
1022 deciding to run some code repeatedly while a condition is true are basic
1023 building blocks in most programming languages. The most common constructs that
1024 let you control the flow of execution of Rust code are `if` expressions and
1027 ### `if` Expressions
1029 An `if` expression allows us to branch our code depending on conditions. We
1030 provide a condition and then state, “If this condition is met, run this block
1031 of code. If the condition is not met, do not run this block of code.”
1033 Create a new project called *branches* in your *projects* directory to explore
1034 the `if` expression. In the *src/main.rs* file, input the following:
1036 Filename: src/main.rs
1043 println!("condition was true");
1045 println!("condition was false");
1050 All `if` expressions start with the keyword `if`, which is followed by a
1051 condition. In this case, the condition checks whether or not the variable
1052 `number` has a value less than 5. The block of code we want to execute if the
1053 condition is true is placed immediately after the condition inside curly
1054 braces. Blocks of code associated with the conditions in `if` expressions are
1055 sometimes called *arms*, just like the arms in `match` expressions that we
1056 discussed in the “Comparing the Guess to the Secret Number” section of Chapter
1057 2. Optionally, we can also include an `else` expression, which we chose to do
1058 here, to give the program an alternative block of code to execute should the
1059 condition evaluate to false. If you don’t provide an `else` expression and the
1060 condition is false, the program will just skip the `if` block and move on to
1061 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 Running `target/debug/branches`
1072 Let’s try changing the value of `number` to a value that makes the condition
1073 `false` to see what happens:
1079 Run the program again, and look at the output:
1083 Compiling branches v0.1.0 (file:///projects/branches)
1084 Running `target/debug/branches`
1088 It’s also worth noting that the condition in this code *must* be a `bool`. To
1089 see what happens if the condition isn’t a `bool`, try running the following
1092 Filename: src/main.rs
1099 println!("number was three");
1104 The `if` condition evaluates to a value of `3` this time, and Rust throws an
1108 error[E0308]: mismatched types
1112 | ^^^^^^ expected bool, found integral variable
1114 = note: expected type `bool`
1115 found type `{integer}`
1118 The error indicates that Rust expected a `bool` but got an integer. Rust will
1119 not automatically try to convert non-boolean types to a boolean, unlike
1120 languages such as Ruby and JavaScript. You must be explicit and always provide
1121 `if` with a `boolean` as its condition. If we want the `if` code block to run
1122 only when a number is not equal to `0`, for example, we can change the `if`
1123 expression to the following:
1125 Filename: src/main.rs
1132 println!("number was something other than zero");
1137 Running this code will print `number was something other than zero`.
1139 #### Multiple Conditions with `else if`
1141 We can have multiple conditions by combining `if` and `else` in an `else if`
1142 expression. For example:
1144 Filename: src/main.rs
1150 if number % 4 == 0 {
1151 println!("number is divisible by 4");
1152 } else if number % 3 == 0 {
1153 println!("number is divisible by 3");
1154 } else if number % 2 == 0 {
1155 println!("number is divisible by 2");
1157 println!("number is not divisible by 4, 3, or 2");
1162 This program has four possible paths it can take. After running it, you should
1163 see the following output:
1167 Compiling branches v0.1.0 (file:///projects/branches)
1168 Running `target/debug/branches`
1169 number is divisible by 3
1172 When this program executes, it checks each `if` expression in turn and executes
1173 the first body for which the condition holds true. Note that even though 6 is
1174 divisible by 2, we don’t see the output `number is divisible by 2`, nor do we
1175 see the `number is not divisible by 4, 3, or 2` text from the `else` block. The
1176 reason is that Rust will only execute the block for the first true condition,
1177 and once it finds one, it won’t even check the rest.
1179 Using too many `else if` expressions can clutter your code, so if you have more
1180 than one, you might want to refactor your code. Chapter 6 describes a powerful
1181 Rust branching construct called `match` for these cases.
1183 #### Using `if` in a `let` statement
1185 Because `if` is an expression, we can use it on the right side of a `let`
1186 statement, for instance in Listing 3-4:
1188 Filename: src/main.rs
1192 let condition = true;
1193 let number = if condition {
1199 println!("The value of number is: {}", number);
1204 Listing 3-4: 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 Running `target/debug/branches`
1214 The value of number is: 5
1217 Remember that blocks of code evaluate to the last expression in them, and
1218 numbers by themselves are also expressions. In this case, the value of the
1219 whole `if` expression depends on which block of code executes. This means the
1220 values that have the potential to be results from each arm of the `if` must be
1221 the same type; in Listing 3-4, the results of both the `if` arm and the `else`
1222 arm were `i32` integers. But what happens if the types are mismatched, as in
1223 the following example?
1225 Filename: src/main.rs
1229 let condition = true;
1231 let number = if condition {
1237 println!("The value of number is: {}", number);
1241 When we try to run this code, we’ll get an error. The `if` and `else` arms have
1242 value types that are incompatible, and Rust indicates exactly where to find the
1243 problem in the program:
1246 error[E0308]: if and else have incompatible types
1247 --> src/main.rs:4:18
1249 4 | let number = if condition {
1250 | __________________^ starting here...
1255 | |_____^ ...ending here: expected integral variable, found reference
1257 = note: expected type `{integer}`
1258 found type `&'static str`
1261 The expression in the `if` block evaluates to an integer, and the expression in
1262 the `else` block evaluates to a string. This won’t work because variables must
1263 have a single type. Rust needs to know at compile time what type the `number`
1264 variable is, definitively, so it can verify at compile time that its type is
1265 valid everywhere we use `number`. Rust wouldn’t be able to do that if the type
1266 of `number` was only determined at runtime; the compiler would be more complex
1267 and would make fewer guarantees about the code if it had to keep track of
1268 multiple hypothetical types for any variable.
1270 ### Repetition with Loops
1272 It’s often useful to execute a block of code more than once. For this task,
1273 Rust provides several *loops*. A loop runs through the code inside the loop
1274 body to the end and then starts immediately back at the beginning. To
1275 experiment with loops, let’s make a new project called *loops*.
1277 Rust has three kinds of loops: `loop`, `while`, and `for`. Let’s try each one.
1279 #### Repeating Code with `loop`
1281 The `loop` keyword tells Rust to execute a block of code over and over again
1282 forever or until you explicitly tell it to stop.
1284 As an example, change the *src/main.rs* file in your *loops* directory to look
1287 Filename: src/main.rs
1297 When we run this program, we’ll see `again!` printed over and over continuously
1298 until we stop the program manually. Most terminals support a keyboard shortcut,
1299 ctrl-C, to halt a program that is stuck in a continual loop. Give it a try:
1303 Compiling loops v0.1.0 (file:///projects/loops)
1304 Running `target/debug/loops`
1312 The symbol `^C` represents where you pressed ctrl-C. You may or may not see the
1313 word `again!` printed after the `^C`, depending on where the code was in the
1314 loop when it received the halt signal.
1316 Fortunately, Rust provides another, more reliable way to break out of a loop.
1317 You can place the `break` keyword within the loop to tell the program when to
1318 stop executing the loop. Recall that we did this in the guessing game in the
1319 “Quitting After a Correct Guess” section of Chapter 2 to exit the
1320 program when the user won the game by guessing the correct number.
1322 #### Conditional Loops with `while`
1324 It’s often useful for a program to evaluate a condition within a loop. While
1325 the condition is true, the loop runs. When the condition ceases to be true, you
1326 call `break`, stopping the loop. This loop type could be implemented using a
1327 combination of `loop`, `if`, `else`, and `break`; you could try that now in a
1328 program, if you’d like.
1330 However, this pattern is so common that Rust has a built-in language construct
1331 for it, and it’s called a `while` loop. The following example uses `while`: the
1332 program loops three times, counting down each time. Then, after the loop, it
1333 prints another message and exits:
1335 Filename: src/main.rs
1342 println!("{}!", number);
1344 number = number - 1;
1347 println!("LIFTOFF!!!");
1351 This construct eliminates a lot of nesting that would be necessary if you used
1352 `loop`, `if`, `else`, and `break`, and it’s clearer. While a condition holds
1353 true, the code runs; otherwise, it exits the loop.
1355 #### Looping Through a Collection with `for`
1357 You could use the `while` construct to loop over the elements of a collection,
1358 such as an array. For example:
1360 Filename: src/main.rs
1364 let a = [10, 20, 30, 40, 50];
1368 println!("the value is: {}", a[index]);
1376 Listing 3-5: Looping through each element of a collection using a `while` loop
1379 Here, the code counts up through the elements in the array. It starts at index
1380 `0`, and then loops until it reaches the final index in the array (that is,
1381 when `index < 5` is no longer true). Running this code will print out every
1382 element in the array:
1386 Compiling loops v0.1.0 (file:///projects/loops)
1387 Running `target/debug/loops`
1395 All five array values appear in the terminal, as expected. Even though `index`
1396 will reach a value of `5` at some point, the loop stops executing before trying
1397 to fetch a sixth value from the array.
1399 But this approach is error prone; we could cause the program to panic if the
1400 index length is incorrect. It’s also slow, because the compiler adds runtime
1401 code to perform the conditional check on every element on every iteration
1404 As a more efficient alternative, you can use a `for` loop and execute some code
1405 for each item in a collection. A `for` loop looks like this:
1407 Filename: src/main.rs
1411 let a = [10, 20, 30, 40, 50];
1413 for element in a.iter() {
1414 println!("the value is: {}", element);
1420 Listing 3-6: Looping through each element of a collection using a `for` loop
1423 When we run this code, we’ll see the same output as in Listing 3-5. More
1424 importantly, we’ve now increased the safety of the code and eliminated the
1425 chance of bugs that might result from going beyond the end of the array or not
1426 going far enough and missing some items.
1428 For example, in the code in Listing 3-5, if you removed an item from the `a`
1429 array but forgot to update the condition to `while index < 4`, the code would
1430 panic. Using the `for` loop, you don’t need to remember to change any other
1431 code if you changed the number of values in the array.
1433 The safety and conciseness of `for` loops make them the most commonly used loop
1434 construct in Rust. Even in situations in which you want to run some code a
1435 certain number of times, as in the countdown example that used a `while` loop
1436 in Listing 3-5, most Rustaceans would use a `for` loop. The way to do that
1437 would be to use a `Range`, which is a type provided by the standard library
1438 that generates all numbers in sequence starting from one number and ending
1439 before another number.
1441 Here’s what the countdown would look like using a `for` loop and another method
1442 we’ve not yet talked about, `rev`, to reverse the range:
1444 Filename: src/main.rs
1448 for number in (1..4).rev() {
1449 println!("{}!", number);
1451 println!("LIFTOFF!!!");
1455 This code is a bit nicer, isn’t it?
1459 You made it! That was a sizable chapter: you learned about variables, scalar
1460 and`if` expressions, and loops! If you want to practice with the concepts
1461 discussed in this chapter, try building programs to do the following:
1463 * Convert temperatures between Fahrenheit and Celsius.
1464 * Generate the nth Fibonacci number.
1465 * Print the lyrics to the Christmas carol “The Twelve Days of Christmas,”
1466 taking advantage of the repetition in the song.
1468 When you’re ready to move on, we’ll talk about a concept in Rust that *doesn’t*
1469 commonly exist in other programming languages: ownership.