# The Rust Programming Language ![rw-book-cover](https://m.media-amazon.com/images/I/71aCEjlQBoL._SY160.jpg) ## Metadata - Author: Steve Klabnik and Carol Nichols - Full Title: The Rust Programming Language - Category: #rust ## Highlights - Run rustup doc to open the local documentation in your browser. ([Location 1571](https://readwise.io/to_kindle?action=open&asin=B0B7QTX8LL&location=1571)) - If you want to stick to a standard style across Rust projects, you can use an automatic formatter tool called rustfmt to format your code in a particular style (more on rustfmt in Appendix D). The Rust team has included this tool with the standard Rust distribution, as rustc is, so it should already be installed on your computer! ([Location 1634](https://readwise.io/to_kindle?action=open&asin=B0B7QTX8LL&location=1634)) - you just need to know that using a ! means that you’re calling a macro instead of a normal function and that macros don’t always follow the same rules as functions. ([Location 1647](https://readwise.io/to_kindle?action=open&asin=B0B7QTX8LL&location=1647)) - Cargo is Rust’s build system and package manager. Most Rustaceans use this tool to manage their Rust projects because Cargo handles a lot of tasks for you, such as building your code, downloading the libraries your code depends on, and building those libraries. ([Location 1686](https://readwise.io/to_kindle?action=open&asin=B0B7QTX8LL&location=1686)) - In Rust, packages of code are referred to as crates. ([Location 1735](https://readwise.io/to_kindle?action=open&asin=B0B7QTX8LL&location=1735)) - Cargo expects your source files to live inside the src directory. The top-level project directory is just for README files, license information, configuration files, and anything else not related to your code. Using Cargo helps you organize your projects. There’s a place for everything, and everything is in its place. ([Location 1745](https://readwise.io/to_kindle?action=open&asin=B0B7QTX8LL&location=1745)) - This command creates an executable file in target/debug/hello_cargo (or target\debug\hello_cargo.exe on Windows) rather than in your current directory. Because the default build is a debug build, Cargo puts the binary in a directory named debug. You can run the executable with this command: ([Location 1756](https://readwise.io/to_kindle?action=open&asin=B0B7QTX8LL&location=1756)) - Cargo.lock. This file keeps track of the exact versions of dependencies in your project. ([Location 1764](https://readwise.io/to_kindle?action=open&asin=B0B7QTX8LL&location=1764)) - Using cargo run is more convenient than having to remember to run cargo build and then use the whole path to the binary, so most developers use cargo run. ([Location 1772](https://readwise.io/to_kindle?action=open&asin=B0B7QTX8LL&location=1772)) - Cargo also provides a command called cargo check. This command quickly checks your code to make sure it compiles but doesn’t produce an executable: ([Location 1781](https://readwise.io/to_kindle?action=open&asin=B0B7QTX8LL&location=1781)) - Why would you not want an executable? Often, cargo check is much faster than cargo build because it skips the step of producing an executable. If you’re continually checking your work while writing the code, using cargo check will speed up the process of letting you know if your project is still compiling! As such, many Rustaceans run cargo check periodically as they write their program to make sure it compiles. Then they run cargo build when they’re ready to use the executable. ([Location 1786](https://readwise.io/to_kindle?action=open&asin=B0B7QTX8LL&location=1786)) - Let’s recap what we’ve learned so far about Cargo: We can create a project using cargo new. We can build a project using cargo build. We can build and run a project in one step using cargo run. We can build a project without producing a binary to check for errors using cargo check. Instead of saving the result of the build in the same directory as our code, Cargo stores it in the target/debug directory. ([Location 1791](https://readwise.io/to_kindle?action=open&asin=B0B7QTX8LL&location=1791)) - When your project is finally ready for release, you can use cargo build --release to compile it with optimizations. This command will create an executable in target/release instead of target/debug. The optimizations make your Rust code run faster, but turning them on lengthens the time it takes for your program to compile. This is why there are two different profiles: one for development, when you want to rebuild quickly and often, and another for building the final program you’ll give to a user that won’t be rebuilt repeatedly and that will run as fast as possible. If you’re benchmarking your code’s running time, be sure to run cargo build --release and benchmark with the executable in target/release. ([Location 1801](https://readwise.io/to_kindle?action=open&asin=B0B7QTX8LL&location=1801)) - By default, Rust has a set of items defined in the standard library that it brings into the scope of every program. This set is called the prelude, ([Location 1881](https://readwise.io/to_kindle?action=open&asin=B0B7QTX8LL&location=1881)) - If a type you want to use isn’t in the prelude, you have to bring that type into scope explicitly with a use statement. ([Location 1884](https://readwise.io/to_kindle?action=open&asin=B0B7QTX8LL&location=1884)) - We use the let statement to create the variable. ([Location 1902](https://readwise.io/to_kindle?action=open&asin=B0B7QTX8LL&location=1902)) - 5. In Rust, variables are immutable by default, meaning once we give the variable a value, the value won’t change. ([Location 1906](https://readwise.io/to_kindle?action=open&asin=B0B7QTX8LL&location=1906)) - The :: syntax in the ::new line indicates that new is an associated function of the String type. An associated function is a function that’s implemented on a type, in this case String. This new function creates a new, empty string. You’ll find a new function on many types because it’s a common name for a function that makes a new value of some kind. ([Location 1922](https://readwise.io/to_kindle?action=open&asin=B0B7QTX8LL&location=1922)) - In full, the let mut guess = String::new(); line has created a mutable variable that is currently bound to a new, empty instance of a String. ([Location 1928](https://readwise.io/to_kindle?action=open&asin=B0B7QTX8LL&location=1928)) - If we hadn’t imported the io library with use std::io; at the beginning of the program, we could still use the function by writing this function call as std::io::stdin. ([Location 1936](https://readwise.io/to_kindle?action=open&asin=B0B7QTX8LL&location=1936)) - Next, the line .read_line(&mut guess) calls the read_line method on the standard input handle to get input from the user. We’re also passing &mut guess as the argument to read_line to tell it what string to store the user input in. ([Location 1941](https://readwise.io/to_kindle?action=open&asin=B0B7QTX8LL&location=1941)) - The & indicates that this argument is a reference, which gives you a way to let multiple parts of your code access one piece of data without needing to copy that data into memory multiple times. ([Location 1946](https://readwise.io/to_kindle?action=open&asin=B0B7QTX8LL&location=1946)) - As mentioned earlier, read_line puts whatever the user enters into the string we pass to it, but it also returns a Result value. Result is an enumeration, often called an enum, which is a type that can be in one of multiple possible states. We call each possible state a variant. ([Location 1962](https://readwise.io/to_kindle?action=open&asin=B0B7QTX8LL&location=1962)) - Result’s variants are Ok and Err. The Ok variant indicates the operation was successful, and inside Ok is the successfully generated value. The Err variant means the operation failed, and Err contains information about how or why the operation failed. ([Location 1969](https://readwise.io/to_kindle?action=open&asin=B0B7QTX8LL&location=1969)) - Values of the Result type, like values of any type, have methods defined on them. An instance of Result has an expect method that you can call. If this instance of Result is an Err value, expect will cause the program to crash and display the message that you passed as an argument to expect. If the read_line method returns an Err, it would likely be the result of an error coming from the underlying operating system. If this instance of Result is an Ok value, expect will take the return value that Ok is holding and return just that value to you so you can use it. ([Location 1973](https://readwise.io/to_kindle?action=open&asin=B0B7QTX8LL&location=1973)) - If you don’t call expect, the program will compile, but you’ll get a warning: ([Location 1983](https://readwise.io/to_kindle?action=open&asin=B0B7QTX8LL&location=1983)) - The {} set of curly brackets is a placeholder: think of {} as little crab pincers that hold a value in place. ([Location 2000](https://readwise.io/to_kindle?action=open&asin=B0B7QTX8LL&location=2000)) - Remember that a crate is a collection of Rust source code files. The project we’ve been building is a binary crate, which is an executable. The rand crate is a library crate, which contains code that is intended to be used in other programs and can’t be executed on its own. ([Location 2022](https://readwise.io/to_kindle?action=open&asin=B0B7QTX8LL&location=2022)) - Cargo’s coordination of external crates is where Cargo really shines. Before we can write code that uses rand, we need to modify the Cargo.toml file to include the rand crate as a dependency. ([Location 2026](https://readwise.io/to_kindle?action=open&asin=B0B7QTX8LL&location=2026)) - Cargo fetches the latest versions of everything that dependency needs from the registry, which is a copy of data from Crates.io ([Location 2056](https://readwise.io/to_kindle?action=open&asin=B0B7QTX8LL&location=2056)) - Cargo has a mechanism that ensures you can rebuild the same artifact every time you or anyone else builds your code: Cargo will use only the versions of the dependencies you specified until you indicate otherwise. For example, say that next week version 0.8.6 of the rand crate comes out, and that version contains an important bug fix, but it also contains a regression that will break your code. To handle this, Rust creates the Cargo.lock file the first time you run cargo build, so we now have this in the guessing_game directory. ([Location 2076](https://readwise.io/to_kindle?action=open&asin=B0B7QTX8LL&location=2076)) - When you build a project for the first time, Cargo figures out all the versions of the dependencies that fit the criteria and then writes them to the Cargo.lock file. ([Location 2081](https://readwise.io/to_kindle?action=open&asin=B0B7QTX8LL&location=2081)) - rand::thread_rng function that gives us the particular random number generator we’re going to use: one that is local to the current thread of execution and is seeded by the operating system. Then we call the gen_range method on the random number generator. This method is defined by the Rng trait that we brought into scope with the use rand::Rng; statement. The gen_range method takes a range expression as an argument and generates a random number in the range. The kind of range expression we’re using here takes the form start..=end and is inclusive on the lower and upper bounds, so we need to specify 1..=100 to request a number between 1 and 100. ([Location 2128](https://readwise.io/to_kindle?action=open&asin=B0B7QTX8LL&location=2128)) - library. The Ordering type is another enum and has the variants Less, Greater, and Equal. These are the three outcomes that are possible when you compare two values. ([Location 2169](https://readwise.io/to_kindle?action=open&asin=B0B7QTX8LL&location=2169)) - A match expression is made up of arms. An arm consists of a pattern to match against, and the code that should be run if the value given to match fits that arm’s pattern. Rust takes the value given to match and looks through each arm’s pattern in turn. Patterns and the match construct are powerful Rust features: they let you express a variety of situations your code might encounter and they make sure you handle them all. ([Location 2181](https://readwise.io/to_kindle?action=open&asin=B0B7QTX8LL&location=2181)) - The core of the error states that there are mismatched types. Rust has a strong, static type system. However, it also has type inference. When we wrote let mut guess = String::new(), Rust was able to infer that guess should be a String and didn’t make us write the type. The secret_number, on the other hand, is a number type. ([Location 2205](https://readwise.io/to_kindle?action=open&asin=B0B7QTX8LL&location=2205)) - We create a variable named guess. But wait, doesn’t the program already have a variable named guess? It does, but helpfully Rust allows us to shadow the previous value of guess with a new one. Shadowing lets us reuse the guess variable name rather than forcing us to create two unique variables, such as guess_str and guess, for example. ([Location 2226](https://readwise.io/to_kindle?action=open&asin=B0B7QTX8LL&location=2226)) - The guess in the expression refers to the original guess variable that contained the input as a string. The trim method on a String instance will eliminate any whitespace at the beginning and end, ([Location 2234](https://readwise.io/to_kindle?action=open&asin=B0B7QTX8LL&location=2234)) - The parse method on strings converts a string to another type. ([Location 2244](https://readwise.io/to_kindle?action=open&asin=B0B7QTX8LL&location=2244)) - The parse method will only work on characters that can logically be converted into numbers and so can easily cause errors. ([Location 2253](https://readwise.io/to_kindle?action=open&asin=B0B7QTX8LL&location=2253)) - We switch from an expect call to a match expression to move from crashing on an error to handling the error. Remember that parse returns a Result type and Result is an enum that has the variants Ok and Err. We’re using a match expression here, as we did with the Ordering result of the cmp method. ([Location 2329](https://readwise.io/to_kindle?action=open&asin=B0B7QTX8LL&location=2329)) - If parse is able to successfully turn the string into a number, it will return an Ok value that contains the resultant number. That Ok value will match the first arm’s pattern, and the match expression will just return the num value that parse produced and put inside the Ok value. That number will end up right where we want it in the new guess variable we’re creating. ([Location 2335](https://readwise.io/to_kindle?action=open&asin=B0B7QTX8LL&location=2335)) - If parse is not able to turn the string into a number, it will return an Err value that contains more information about the error. The Err value does not match the Ok(num) pattern in the first match arm, but it does match the Err(_) pattern in the second arm. The underscore, _, is a catch-all value; in this example, we’re saying we want to match all Err values, no matter what information they have inside them. So the program will execute the second arm’s code, continue, which tells the program to go to the next iteration of the loop and ask for another guess. ([Location 2341](https://readwise.io/to_kindle?action=open&asin=B0B7QTX8LL&location=2341)) - variables are immutable. ([Location 2401](https://readwise.io/to_kindle?action=open&asin=B0B7QTX8LL&location=2401)) - When a variable is immutable, once a value is bound to a name, you can’t change that value. ([Location 2404](https://readwise.io/to_kindle?action=open&asin=B0B7QTX8LL&location=2404)) - Compiler errors can be frustrating, but really they only mean your program isn’t safely doing what you want it to do yet; ([Location 2421](https://readwise.io/to_kindle?action=open&asin=B0B7QTX8LL&location=2421)) - Like immutable variables, constants are values that are bound to a name and are not allowed to change, but there are a few differences between constants and variables. ([Location 2450](https://readwise.io/to_kindle?action=open&asin=B0B7QTX8LL&location=2450)) - constants are values that are bound to a name and are not allowed to change, ([Location 2450](https://readwise.io/to_kindle?action=open&asin=B0B7QTX8LL&location=2450)) - Constants can be declared in any scope, including the global scope, which makes them useful for values that many parts of code need to know about. ([Location 2457](https://readwise.io/to_kindle?action=open&asin=B0B7QTX8LL&location=2457)) - The last difference is that constants may be set only to a constant expression, not the result of a value that could only be computed at runtime. ([Location 2459](https://readwise.io/to_kindle?action=open&asin=B0B7QTX8LL&location=2459)) - Rust’s naming convention for constants is to use all uppercase with underscores between words. ([Location 2465](https://readwise.io/to_kindle?action=open&asin=B0B7QTX8LL&location=2465)) - Constants are valid for the entire time a program runs, within the scope in which they were declared. ([Location 2470](https://readwise.io/to_kindle?action=open&asin=B0B7QTX8LL&location=2470)) - the second variable overshadows the first, taking any uses of the variable name to itself until either it itself is shadowed or the scope ends. ([Location 2479](https://readwise.io/to_kindle?action=open&asin=B0B7QTX8LL&location=2479)) - Shadowing is different from marking a variable as mut because we’ll get a compile-time error if we accidentally try to reassign to this variable without using the let keyword. By using let, we can perform a few transformations on a value but have the variable be immutable after those transformations have been completed. ([Location 2499](https://readwise.io/to_kindle?action=open&asin=B0B7QTX8LL&location=2499)) - The other difference between mut and shadowing is that because we’re effectively creating a new variable when we use the let keyword again, we can change the type of the value but reuse the same name. ([Location 2502](https://readwise.io/to_kindle?action=open&asin=B0B7QTX8LL&location=2502)) - data type, which tells Rust what kind of data is being specified so it knows how to work with that data. ([Location 2523](https://readwise.io/to_kindle?action=open&asin=B0B7QTX8LL&location=2523)) - Keep in mind that Rust is a statically typed language, which means that it must know the types of all variables at compile time. ([Location 2525](https://readwise.io/to_kindle?action=open&asin=B0B7QTX8LL&location=2525)) - A scalar type represents a single value. Rust has four primary scalar types: integers, floating-point numbers, Booleans, and characters. ([Location 2540](https://readwise.io/to_kindle?action=open&asin=B0B7QTX8LL&location=2540)) - An integer is a number without a fractional component. ([Location 2543](https://readwise.io/to_kindle?action=open&asin=B0B7QTX8LL&location=2543)) - unsigned integer (signed integer types start with i instead of u) that takes up 32 bits of space. ([Location 2546](https://readwise.io/to_kindle?action=open&asin=B0B7QTX8LL&location=2546)) - Signed and unsigned refer to whether it’s possible for the number to be negative—in other words, whether the number needs to have a sign with it (signed) or whether it will only ever be positive and can therefore be represented without a sign (unsigned). ([Location 2567](https://readwise.io/to_kindle?action=open&asin=B0B7QTX8LL&location=2567)) - Each signed variant can store numbers from –(2n – 1) to 2n – 1 – 1 inclusive, where n is the number of bits that variant uses. So an i8 can store numbers from –(27) to 27 – 1, which equals –128 to 127. Unsigned variants can store numbers from 0 to 2n – 1, so a u8 can store numbers from 0 to 28 – 1, which equals 0 to 255. ([Location 2571](https://readwise.io/to_kindle?action=open&asin=B0B7QTX8LL&location=2571)) - So how do you know which type of integer to use? If you’re unsure, Rust’s defaults are generally good places to start: integer types default to i32. ([Location 2597](https://readwise.io/to_kindle?action=open&asin=B0B7QTX8LL&location=2597)) - When you’re compiling in release mode with the --release flag, Rust does not include checks for integer overflow that cause panics. ([Location 2608](https://readwise.io/to_kindle?action=open&asin=B0B7QTX8LL&location=2608)) - Rust also has two primitive types for floating-point numbers, which are numbers with decimal points. Rust’s floating-point types are f32 and f64, which are 32 bits and 64 bits in size, respectively. The default type is f64 because on modern CPUs, it’s roughly the same speed as f32 but is capable of more precision. All floating-point types are signed. ([Location 2622](https://readwise.io/to_kindle?action=open&asin=B0B7QTX8LL&location=2622)) - As in most other programming languages, a Boolean type in Rust has two possible values: true and false. Booleans are one byte in size. ([Location 2646](https://readwise.io/to_kindle?action=open&asin=B0B7QTX8LL&location=2646)) - Rust’s char type is the language’s most primitive alphabetic type. ([Location 2657](https://readwise.io/to_kindle?action=open&asin=B0B7QTX8LL&location=2657)) - Note that we specify char literals with single quotes, as opposed to string literals, which use double ([Location 2663](https://readwise.io/to_kindle?action=open&asin=B0B7QTX8LL&location=2663)) - Compound types can group multiple values into one type. Rust has two primitive compound types: tuples and ([Location 2673](https://readwise.io/to_kindle?action=open&asin=B0B7QTX8LL&location=2673)) - A tuple is a general way of grouping together a number of values with a variety of types into one compound type. Tuples have a fixed length: once declared, they cannot grow or shrink in size. ([Location 2675](https://readwise.io/to_kindle?action=open&asin=B0B7QTX8LL&location=2675)) - We create a tuple by writing a comma-separated list of values inside parentheses. ([Location 2677](https://readwise.io/to_kindle?action=open&asin=B0B7QTX8LL&location=2677)) - The variable tup binds to the entire tuple because a tuple is considered a single compound element. ([Location 2682](https://readwise.io/to_kindle?action=open&asin=B0B7QTX8LL&location=2682)) - tup. It then uses a pattern with let to take tup and turn it into three separate variables, x, y, and z. This is called destructuring because it breaks the single tuple into three parts. ([Location 2689](https://readwise.io/to_kindle?action=open&asin=B0B7QTX8LL&location=2689)) - We can also access a tuple element directly by using a period (.) followed by the index of the value we want to access. ([Location 2694](https://readwise.io/to_kindle?action=open&asin=B0B7QTX8LL&location=2694)) - The tuple without any values has a special name, unit. ([Location 2702](https://readwise.io/to_kindle?action=open&asin=B0B7QTX8LL&location=2702)) - Another way to have a collection of multiple values is with an array. Unlike a tuple, every element of an array must have the same type. Unlike arrays in some other languages, arrays in Rust have a fixed length. ([Location 2706](https://readwise.io/to_kindle?action=open&asin=B0B7QTX8LL&location=2706)) - Arrays are useful when you want your data allocated on the stack rather than the heap (we will discuss the stack and the heap more in Chapter 4) or when you want to ensure you always have a fixed number of elements. ([Location 2712](https://readwise.io/to_kindle?action=open&asin=B0B7QTX8LL&location=2712)) - A vector is a similar collection type provided by the standard library that is allowed to grow or shrink in size. If you’re unsure whether to use an array or a vector, chances are you should use a vector. ([Location 2714](https://readwise.io/to_kindle?action=open&asin=B0B7QTX8LL&location=2714)) - However, arrays are more useful when you know the number of elements will not need to change. ([Location 2717](https://readwise.io/to_kindle?action=open&asin=B0B7QTX8LL&location=2717)) - You write an array’s type using square brackets with the type of each element, a semicolon, and then the number of elements in the array, ([Location 2722](https://readwise.io/to_kindle?action=open&asin=B0B7QTX8LL&location=2722)) - You can also initialize an array to contain the same value for each element by specifying the initial value, followed by a semicolon, and then the length of the array in square brackets, ([Location 2727](https://readwise.io/to_kindle?action=open&asin=B0B7QTX8LL&location=2727)) - An array is a single chunk of memory of a known, fixed size that can be allocated on the stack. You can access elements of an array using indexing, ([Location 2735](https://readwise.io/to_kindle?action=open&asin=B0B7QTX8LL&location=2735)) - The program resulted in a runtime error at the point of using an invalid value in the indexing operation. ([Location 2762](https://readwise.io/to_kindle?action=open&asin=B0B7QTX8LL&location=2762)) - the main function, which is the entry point of many programs. ([Location 2773](https://readwise.io/to_kindle?action=open&asin=B0B7QTX8LL&location=2773)) - You’ve also seen the fn keyword, which allows you to declare new functions. ([Location 2774](https://readwise.io/to_kindle?action=open&asin=B0B7QTX8LL&location=2774)) - Rust code uses snake case as the conventional style for function and variable names, in which all letters are lowercase and underscores separate words. ([Location 2776](https://readwise.io/to_kindle?action=open&asin=B0B7QTX8LL&location=2776)) - We can define functions to have parameters, which are special variables that are part of a function’s signature. When a function has parameters, you can provide it with concrete values for those parameters. Technically, the concrete values are called arguments, but in casual conversation, people tend to use the words parameter and argument interchangeably for either the variables in a function’s definition or the concrete values passed in when you call a function. ([Location 2798](https://readwise.io/to_kindle?action=open&asin=B0B7QTX8LL&location=2798)) - In function signatures, you must declare the type of each parameter. This is a deliberate decision in Rust’s design: requiring type annotations in function definitions means the compiler almost never needs you to use them elsewhere in the code to figure out what type you mean. ([Location 2818](https://readwise.io/to_kindle?action=open&asin=B0B7QTX8LL&location=2818)) - Function bodies are made up of a series of statements optionally ending in an expression. ([Location 2841](https://readwise.io/to_kindle?action=open&asin=B0B7QTX8LL&location=2841)) - So far, the functions we’ve covered haven’t included an ending expression, but you have seen an expression as part of a statement. Because Rust is an expression-based language, this is an important distinction to understand. Other languages don’t have the same distinctions, so let’s look at what statements and expressions are and how their differences affect the bodies of functions. ([Location 2841](https://readwise.io/to_kindle?action=open&asin=B0B7QTX8LL&location=2841)) - Statements are instructions that perform some action and do not return a value. Expressions evaluate to a resultant value. ([Location 2845](https://readwise.io/to_kindle?action=open&asin=B0B7QTX8LL&location=2845)) - Function definitions are also statements; ([Location 2854](https://readwise.io/to_kindle?action=open&asin=B0B7QTX8LL&location=2854)) - Statements do not return values. ([Location 2856](https://readwise.io/to_kindle?action=open&asin=B0B7QTX8LL&location=2856)) - The let y = 6 statement does not return a value, so there isn’t anything for x to bind to. ([Location 2868](https://readwise.io/to_kindle?action=open&asin=B0B7QTX8LL&location=2868)) - Expressions evaluate to a value and make up most of the rest of the code that you’ll write in Rust. ([Location 2873](https://readwise.io/to_kindle?action=open&asin=B0B7QTX8LL&location=2873)) - 6. Calling a function is an expression. Calling a macro is an expression. ([Location 2877](https://readwise.io/to_kindle?action=open&asin=B0B7QTX8LL&location=2877)) - Expressions do not include ending semicolons. If you add a semicolon to the end of an expression, you turn it into a statement, and it will then not return a value. Keep this in mind as you explore function return values and expressions next. ([Location 2887](https://readwise.io/to_kindle?action=open&asin=B0B7QTX8LL&location=2887)) - Functions can return values to the code that calls them. We don’t name return values, but we must declare their type after an arrow (->). ([Location 2890](https://readwise.io/to_kindle?action=open&asin=B0B7QTX8LL&location=2890)) - In Rust, the return value of the function is synonymous with the value of the final expression in the block of the body of a function. You can return early from a function by using the return keyword and specifying a value, but most functions return the last expression implicitly. ([Location 2892](https://readwise.io/to_kindle?action=open&asin=B0B7QTX8LL&location=2892)) - There are no function calls, macros, or even let statements in the five function—just the number 5 by itself. That’s a perfectly valid function in Rust. ([Location 2899](https://readwise.io/to_kindle?action=open&asin=B0B7QTX8LL&location=2899)) - Second, the five function has no parameters and defines the type of the return value, but the body of the function is a lonely 5 with no semicolon because it’s an expression whose value we want to return. ([Location 2912](https://readwise.io/to_kindle?action=open&asin=B0B7QTX8LL&location=2912)) - Running this code will print The value of x is: 6. But if we place a semicolon at the end of the line containing x + 1, changing it from an expression to a statement, ([Location 2919](https://readwise.io/to_kindle?action=open&asin=B0B7QTX8LL&location=2919)) - In these cases, programmers leave comments in their source code that the compiler will ignore but people reading the source code may find useful. ([Location 2939](https://readwise.io/to_kindle?action=open&asin=B0B7QTX8LL&location=2939)) - Comments can also be placed at the end of lines containing code: ([Location 2948](https://readwise.io/to_kindle?action=open&asin=B0B7QTX8LL&location=2948)) - But you’ll more often see them used in this format, with the comment on a separate line above the code it’s annotating: ([Location 2952](https://readwise.io/to_kindle?action=open&asin=B0B7QTX8LL&location=2952)) - The ability to run some code depending on whether a condition is true and to run some code repeatedly while a condition is true are basic building blocks in most programming languages. The most common constructs that let you control the flow of execution of Rust code are if expressions and loops. ([Location 2960](https://readwise.io/to_kindle?action=open&asin=B0B7QTX8LL&location=2960)) - An if expression allows you to branch your code depending on conditions. ([Location 2964](https://readwise.io/to_kindle?action=open&asin=B0B7QTX8LL&location=2964)) - All if expressions start with the keyword if, followed by a condition. ([Location 2974](https://readwise.io/to_kindle?action=open&asin=B0B7QTX8LL&location=2974)) - integer. Unlike languages such as Ruby and JavaScript, Rust will not automatically try to convert non-Boolean types to a Boolean. ([Location 3009](https://readwise.io/to_kindle?action=open&asin=B0B7QTX8LL&location=3009)) - You can use multiple conditions by combining if and else in an else if expression. ([Location 3020](https://readwise.io/to_kindle?action=open&asin=B0B7QTX8LL&location=3020)) - Using too many else if expressions can clutter your code, so if you have more than one, you might want to refactor your code. ([Location 3039](https://readwise.io/to_kindle?action=open&asin=B0B7QTX8LL&location=3039)) - Because if is an expression, we can use it on the right side of a let statement to assign the outcome to a variable, ([Location 3043](https://readwise.io/to_kindle?action=open&asin=B0B7QTX8LL&location=3043)) - Remember that blocks of code evaluate to the last expression in them, and numbers by themselves are also expressions. In this case, the value of the whole if expression depends on which block of code executes. This means the values that have the potential to be results from each arm of the if must be the same type; ([Location 3057](https://readwise.io/to_kindle?action=open&asin=B0B7QTX8LL&location=3057)) - It’s often useful to execute a block of code more than once. For this task, Rust provides several loops, which will run through the code inside the loop body to the end and then start immediately back at the beginning. ([Location 3084](https://readwise.io/to_kindle?action=open&asin=B0B7QTX8LL&location=3084)) - Rust also provides a way to break out of a loop using code. You can place the break keyword within the loop to tell the program when to stop executing the loop. ([Location 3105](https://readwise.io/to_kindle?action=open&asin=B0B7QTX8LL&location=3105)) - We also used continue in the guessing game, which in a loop tells the program to skip over any remaining code in this iteration of the loop and go to the next iteration. ([Location 3109](https://readwise.io/to_kindle?action=open&asin=B0B7QTX8LL&location=3109)) - Then we declare a variable named result to hold the value returned from the loop. On every iteration of the loop, we add 1 to the counter variable, and then check whether the counter is equal to 10. When it is, we use the break keyword with the value counter * 2. After the loop, we use a semicolon to end the statement that assigns the value to result. ([Location 3122](https://readwise.io/to_kindle?action=open&asin=B0B7QTX8LL&location=3122)) - If you have loops within loops, break and continue apply to the innermost loop at that point. You can optionally specify a loop label on a loop that you can then use with break or continue to specify that those keywords apply to the labeled loop instead of the innermost loop. Loop labels must begin with a single quote. ([Location 3130](https://readwise.io/to_kindle?action=open&asin=B0B7QTX8LL&location=3130)) - A program will often need to evaluate a condition within a loop. While the condition is true, the loop runs. When the condition ceases to be true, the program calls break, stopping the loop. It’s possible to implement behavior like this using a combination of loop, if, else, and break; ([Location 3151](https://readwise.io/to_kindle?action=open&asin=B0B7QTX8LL&location=3151)) - This construct eliminates a lot of nesting that would be necessary if you used loop, if, else, and break, and it’s clearer. While a condition evaluates to true, the code runs; otherwise, it exits the loop. ([Location 3166](https://readwise.io/to_kindle?action=open&asin=B0B7QTX8LL&location=3166)) - You can choose to use the while construct to loop over the elements of a collection, such as an array. ([Location 3171](https://readwise.io/to_kindle?action=open&asin=B0B7QTX8LL&location=3171)) - However, this approach is error prone; we could cause the program to panic if the index value or test condition is incorrect. For example, if you changed the definition of the a array to have four elements but forgot to update the condition to while index < 4, ([Location 3190](https://readwise.io/to_kindle?action=open&asin=B0B7QTX8LL&location=3190)) - As a more concise alternative, you can use a for loop and execute some code for each item in a collection. ([Location 3195](https://readwise.io/to_kindle?action=open&asin=B0B7QTX8LL&location=3195)) - The safety and conciseness of for loops make them the most commonly used loop construct in Rust. ([Location 3209](https://readwise.io/to_kindle?action=open&asin=B0B7QTX8LL&location=3209)) - Ownership is Rust’s most unique feature and has deep implications for the rest of the language. It enables Rust to make memory safety guarantees without needing a garbage collector, so it’s important to understand how ownership works. ([Location 3232](https://readwise.io/to_kindle?action=open&asin=B0B7QTX8LL&location=3232)) - Ownership is a set of rules that govern how a Rust program manages memory. ([Location 3237](https://readwise.io/to_kindle?action=open&asin=B0B7QTX8LL&location=3237)) - Some languages have garbage collection that regularly looks for no-longer-used memory as the program runs; in other languages, the programmer must explicitly allocate and free the memory. Rust uses a third approach: memory is managed through a system of ownership with a set of rules that the compiler checks. If any of the rules are violated, the program won’t compile. None of the features of ownership will slow down your program while it’s running. ([Location 3238](https://readwise.io/to_kindle?action=open&asin=B0B7QTX8LL&location=3238)) - The stack stores values in the order it gets them and removes the values in the opposite order. This is referred to as last in, first out. ([Location 3252](https://readwise.io/to_kindle?action=open&asin=B0B7QTX8LL&location=3252)) - The heap is less organized: when you put data on the heap, you request a certain amount of space. The memory allocator finds an empty spot in the heap that is big enough, marks it as being in use, and returns a pointer, which is the address of that location. This process is called allocating on the heap and is sometimes abbreviated as just allocating (pushing values onto the stack is not considered allocating). ([Location 3258](https://readwise.io/to_kindle?action=open&asin=B0B7QTX8LL&location=3258)) - Pushing to the stack is faster than allocating on the heap because the allocator never has to search for a place to store new data; that location is always at the top of the stack. ([Location 3266](https://readwise.io/to_kindle?action=open&asin=B0B7QTX8LL&location=3266)) - Accessing data in the heap is slower than accessing data on the stack because you have to follow a pointer to get there. Contemporary processors are faster if they jump around less in memory. ([Location 3269](https://readwise.io/to_kindle?action=open&asin=B0B7QTX8LL&location=3269)) - When your code calls a function, the values passed into the function (including, potentially, pointers to data on the heap) and the function’s local variables get pushed onto the stack. When the function is over, those values get popped off the stack. ([Location 3274](https://readwise.io/to_kindle?action=open&asin=B0B7QTX8LL&location=3274)) - Keeping track of what parts of code are using what data on the heap, minimizing the amount of duplicate data on the heap, and cleaning up unused data on the heap so you don’t run out of space are all problems that ownership addresses. Once you understand ownership, you won’t need to think about the stack and the heap very often, but knowing that the main purpose of ownership is to manage heap data can help explain why it works the way it does. ([Location 3276](https://readwise.io/to_kindle?action=open&asin=B0B7QTX8LL&location=3276)) - Each value in Rust has an owner. There can only be one owner at a time. When the owner goes out of scope, the value will be dropped. ([Location 3283](https://readwise.io/to_kindle?action=open&asin=B0B7QTX8LL&location=3283)) - When s comes into scope, it is valid. It remains valid until it goes out of scope. ([Location 3304](https://readwise.io/to_kindle?action=open&asin=B0B7QTX8LL&location=3304)) - The types covered previously are of a known size, can be stored on the stack and popped off the stack when their scope is over, and can be quickly and trivially copied to make a new, independent instance if another part of code needs to use the same value in a different scope. But we want to look at data that is stored on the heap and explore how Rust knows when to clean up that data, and the String type is a great example. ([Location 3311](https://readwise.io/to_kindle?action=open&asin=B0B7QTX8LL&location=3311)) - We’ve already seen string literals, where a string value is hardcoded into our program. String literals are convenient, but they aren’t suitable for every situation in which we may want to use text. One reason is that they’re immutable. ([Location 3318](https://readwise.io/to_kindle?action=open&asin=B0B7QTX8LL&location=3318)) - Rust has a second string type, String. This type manages data allocated on the heap and as such is able to store an amount of text that is unknown to us at compile time. You can create a String from a string literal using the from function, ([Location 3320](https://readwise.io/to_kindle?action=open&asin=B0B7QTX8LL&location=3320)) - The double colon :: operator allows us to namespace this particular from function under the String type rather than using some sort of name like string_from. ([Location 3325](https://readwise.io/to_kindle?action=open&asin=B0B7QTX8LL&location=3325)) - In the case of a string literal, we know the contents at compile time, so the text is hardcoded directly into the final executable. This is why string literals are fast and efficient. But these properties only come from the string literal’s immutability. ([Location 3338](https://readwise.io/to_kindle?action=open&asin=B0B7QTX8LL&location=3338)) - With the String type, in order to support a mutable, growable piece of text, we need to allocate an amount of memory on the heap, unknown at compile time, to hold the contents. This means: The memory must be requested from the memory allocator at runtime. We need a way of returning this memory to the allocator when we’re done with our String. ([Location 3341](https://readwise.io/to_kindle?action=open&asin=B0B7QTX8LL&location=3341)) - Rust takes a different path: the memory is automatically returned once the variable that owns it goes out of scope. ([Location 3353](https://readwise.io/to_kindle?action=open&asin=B0B7QTX8LL&location=3353)) - There is a natural point at which we can return the memory our String needs to the allocator: when s goes out of scope. When a variable goes out of scope, Rust calls a special function for us. This function is called drop, and it’s where the author of String can put the code to return the memory. Rust calls drop automatically at the closing curly bracket. ([Location 3360](https://readwise.io/to_kindle?action=open&asin=B0B7QTX8LL&location=3360)) - A String is made up of three parts, shown on the left: a pointer to the memory that holds the contents of the string, a length, and a capacity. This group of data is stored on the stack. On the right is the memory on the heap that holds the contents. ([Location 3392](https://readwise.io/to_kindle?action=open&asin=B0B7QTX8LL&location=3392)) - When we assign s1 to s2, the String data is copied, meaning we copy the pointer, the length, and the capacity that are on the stack. We do not copy the data on the heap that the pointer refers to. ([Location 3404](https://readwise.io/to_kindle?action=open&asin=B0B7QTX8LL&location=3404)) - If Rust did this, the operation s2 = s1 could be very expensive in terms of runtime performance if the data on the heap were large. ([Location 3414](https://readwise.io/to_kindle?action=open&asin=B0B7QTX8LL&location=3414)) - Earlier, we said that when a variable goes out of scope, Rust automatically calls the drop function and cleans up the heap memory for that variable. But Figure 4-2 shows both data pointers pointing to the same location. This is a problem: when s2 and s1 go out of scope, they will both try to free the same memory. This is known as a double free error and is one of the memory safety bugs we mentioned previously. Freeing memory twice can lead to memory corruption, which can potentially lead to security vulnerabilities. ([Location 3420](https://readwise.io/to_kindle?action=open&asin=B0B7QTX8LL&location=3420)) - To ensure memory safety, after the line let s2 = s1;, Rust considers s1 as no longer valid. ([Location 3426](https://readwise.io/to_kindle?action=open&asin=B0B7QTX8LL&location=3426)) - If you’ve heard the terms shallow copy and deep copy while working with other languages, the concept of copying the pointer, length, and capacity without copying the data probably sounds like making a shallow copy. But because Rust also invalidates the first variable, instead of being called a shallow copy, it’s known as a move. In this example, we would say that s1 was moved into s2. ([Location 3439](https://readwise.io/to_kindle?action=open&asin=B0B7QTX8LL&location=3439)) - Rust will never automatically create “deep” copies of your data. Therefore, any automatic copying can be assumed to be inexpensive in terms of runtime performance. ([Location 3452](https://readwise.io/to_kindle?action=open&asin=B0B7QTX8LL&location=3452)) - If we do want to deeply copy the heap data of the String, not just the stack data, we can use a common method called clone. ([Location 3455](https://readwise.io/to_kindle?action=open&asin=B0B7QTX8LL&location=3455)) - When you see a call to clone, you know that some arbitrary code is being executed and that code may be expensive. It’s a visual indicator that something different is going on. ([Location 3464](https://readwise.io/to_kindle?action=open&asin=B0B7QTX8LL&location=3464)) - The reason is that types such as integers that have a known size at compile time are stored entirely on the stack, so copies of the actual values are quick to make. That means there’s no reason we would want to prevent x from being valid after we create the variable y. In other words, there’s no difference between deep and shallow copying here, so calling clone wouldn’t do anything different from the usual shallow copying, and we can leave it out. ([Location 3473](https://readwise.io/to_kindle?action=open&asin=B0B7QTX8LL&location=3473)) - So, what types implement the Copy trait? You can check the documentation for the given type to be sure, but as a general rule, any group of simple scalar values can implement Copy, and nothing that requires allocation or is some form of resource can implement Copy. Here are some of the types that implement Copy: All the integer types, such as u32. The Boolean type, bool, with values true and false. All the floating-point types, such as f64. The character type, char. Tuples, if they only contain types that also implement Copy. For example, (i32, i32) implements Copy, but (i32, String) does not. ([Location 3486](https://readwise.io/to_kindle?action=open&asin=B0B7QTX8LL&location=3486)) - If we tried to use s after the call to takes_ownership, Rust would throw a compile-time error. ([Location 3516](https://readwise.io/to_kindle?action=open&asin=B0B7QTX8LL&location=3516)) - Returning values can also transfer ownership. ([Location 3521](https://readwise.io/to_kindle?action=open&asin=B0B7QTX8LL&location=3521)) - While this works, taking ownership and then returning ownership with every function is a bit tedious. ([Location 3548](https://readwise.io/to_kindle?action=open&asin=B0B7QTX8LL&location=3548)) - But this is too much ceremony and a lot of work for a concept that should be common. Luckily for us, Rust has a feature for using a value without transferring ownership, called references. ([Location 3559](https://readwise.io/to_kindle?action=open&asin=B0B7QTX8LL&location=3559)) - A reference is like a pointer in that it’s an address we can follow to access the data stored at that address; that data is owned by some other variable. Unlike a pointer, a reference is guaranteed to point to a valid value of a particular type for the life of that reference. ([Location 3567](https://readwise.io/to_kindle?action=open&asin=B0B7QTX8LL&location=3567)) - First, notice that all the tuple code in the variable declaration and the function return value is gone. Second, note that we pass &s1 into calculate_length and, in its definition, we take &String rather than String. These ampersands represent references, and they allow you to refer to some value without taking ownership of it. ([Location 3576](https://readwise.io/to_kindle?action=open&asin=B0B7QTX8LL&location=3576)) - The opposite of referencing by using & is dereferencing, which is accomplished with the dereference operator, *. ([Location 3587](https://readwise.io/to_kindle?action=open&asin=B0B7QTX8LL&location=3587)) - The &s1 syntax lets us create a reference that refers to the value of s1 but does not own it. Because it does not own it, the value it points to will not be dropped when the reference stops being used. Likewise, the signature of the function uses & to indicate that the type of the parameter s is a reference. ([Location 3595](https://readwise.io/to_kindle?action=open&asin=B0B7QTX8LL&location=3595)) - The scope in which the variable s is valid is the same as any function parameter’s scope, but the value pointed to by the reference is not dropped when s stops being used, because s doesn’t have ownership. When functions have references as parameters instead of the actual values, we won’t need to return the values in order to give back ownership, because we never had ownership. ([Location 3603](https://readwise.io/to_kindle?action=open&asin=B0B7QTX8LL&location=3603)) - We call the action of creating a reference borrowing. ([Location 3607](https://readwise.io/to_kindle?action=open&asin=B0B7QTX8LL&location=3607)) - Just as variables are immutable by default, so are references. ([Location 3622](https://readwise.io/to_kindle?action=open&asin=B0B7QTX8LL&location=3622)) - We can fix the code from Listing 4-6 to allow us to modify a borrowed value with just a few small tweaks that use, instead, a mutable reference: ([Location 3625](https://readwise.io/to_kindle?action=open&asin=B0B7QTX8LL&location=3625)) - Then we create a mutable reference with &mut s where we call the change function, and update the function signature to accept a mutable reference with some_string: &mut String. ([Location 3635](https://readwise.io/to_kindle?action=open&asin=B0B7QTX8LL&location=3635)) - Mutable references have one big restriction: if you have a mutable reference to a value, you can have no other references to that value. ([Location 3638](https://readwise.io/to_kindle?action=open&asin=B0B7QTX8LL&location=3638)) - The restriction preventing multiple mutable references to the same data at the same time allows for mutation but in a very controlled fashion. It’s something that new Rustaceans struggle with because most languages let you mutate whenever you’d like. ([Location 3654](https://readwise.io/to_kindle?action=open&asin=B0B7QTX8LL&location=3654)) - A data race is similar to a race condition and happens when these three behaviors occur: Two or more pointers access the same data at the same time. At least one of the pointers is being used to write to the data. There’s no mechanism being used to synchronize access to the data. ([Location 3657](https://readwise.io/to_kindle?action=open&asin=B0B7QTX8LL&location=3657)) - As always, we can use curly brackets to create a new scope, allowing for multiple mutable references, just not simultaneous ones: ([Location 3662](https://readwise.io/to_kindle?action=open&asin=B0B7QTX8LL&location=3662)) - Rust enforces a similar rule for combining mutable and immutable references. ([Location 3667](https://readwise.io/to_kindle?action=open&asin=B0B7QTX8LL&location=3667)) - We also cannot have a mutable reference while we have an immutable one to the same value. ([Location 3677](https://readwise.io/to_kindle?action=open&asin=B0B7QTX8LL&location=3677)) - The scopes of the immutable references r1 and r2 end after the println! where they are last used, which is before the mutable reference r3 is created. These scopes don’t overlap, so this code is allowed: the compiler can tell that the reference is no longer being used at a point before the end of the scope. ([Location 3687](https://readwise.io/to_kindle?action=open&asin=B0B7QTX8LL&location=3687)) - In languages with pointers, it’s easy to erroneously create a dangling pointer—a pointer that references a location in memory that may have been given to someone else—by freeing some memory while preserving a pointer to that memory. In Rust, by contrast, the compiler guarantees that references will never be dangling references: if you have a reference to some data, the compiler will ensure that the data will not go out of scope before the reference to the data does. ([Location 3695](https://readwise.io/to_kindle?action=open&asin=B0B7QTX8LL&location=3695)) - Because s is created inside dangle, when the code of dangle is finished, s will be deallocated. But we tried to return a reference to it. That means this reference would be pointing to an invalid String. ([Location 3720](https://readwise.io/to_kindle?action=open&asin=B0B7QTX8LL&location=3720)) - Let’s recap what we’ve discussed about references: At any given time, you can have either one mutable reference or any number of immutable references. References must always be valid. ([Location 3730](https://readwise.io/to_kindle?action=open&asin=B0B7QTX8LL&location=3730)) - Slices let you reference a contiguous sequence of elements in a collection rather than the whole collection. A slice is a kind of reference, so it does not have ownership. ([Location 3735](https://readwise.io/to_kindle?action=open&asin=B0B7QTX8LL&location=3735)) - Because we need to go through the String element by element and check whether a value is a space, we’ll convert our String to an array of bytes using the as_bytes method ❶. ([Location 3755](https://readwise.io/to_kindle?action=open&asin=B0B7QTX8LL&location=3755)) - know that iter is a method that returns each element in a collection and that enumerate wraps the result of iter and returns each element as part of a tuple instead. The first element of the tuple returned from enumerate is the index, and the second element is a reference to the element. ([Location 3760](https://readwise.io/to_kindle?action=open&asin=B0B7QTX8LL&location=3760)) - Because the enumerate method returns a tuple, we can use patterns to destructure that tuple. ([Location 3765](https://readwise.io/to_kindle?action=open&asin=B0B7QTX8LL&location=3765)) - String slice range indices must occur at valid UTF-8 character boundaries. If you attempt to create a string slice in the middle of a multibyte character, your program will exit with an error. ([Location 3836](https://readwise.io/to_kindle?action=open&asin=B0B7QTX8LL&location=3836)) - point. Rust disallows the mutable reference in clear and the immutable reference in word from existing at the same time, and compilation fails. Not only has Rust made our API easier to use, but it has also eliminated an entire class of errors at compile time! ([Location 3879](https://readwise.io/to_kindle?action=open&asin=B0B7QTX8LL&location=3879)) - The type of s here is &str: it’s a slice pointing to that specific point of the binary. This is also why string literals are immutable; &str is an immutable reference. ([Location 3886](https://readwise.io/to_kindle?action=open&asin=B0B7QTX8LL&location=3886)) - Defining a function to take a string slice instead of a reference to a String makes our API more general and useful without losing any functionality: ([Location 3906](https://readwise.io/to_kindle?action=open&asin=B0B7QTX8LL&location=3906)) - The concepts of ownership, borrowing, and slices ensure memory safety in Rust programs at compile time. The Rust language gives you control over your memory usage in the same way as other systems’ programming languages, but having the owner of data automatically clean up that data when the owner goes out of scope means you don’t have to write and debug extra code to get this control. ([Location 3929](https://readwise.io/to_kindle?action=open&asin=B0B7QTX8LL&location=3929)) - A struct, or structure, is a custom data type that lets you package together and name multiple related values that make up a meaningful group. If you’re familiar with an object-oriented language, a struct is like an object’s data attributes. ([Location 3939](https://readwise.io/to_kindle?action=open&asin=B0B7QTX8LL&location=3939)) - values. Like tuples, the pieces of a struct can be different types. Unlike with tuples, in a struct you’ll name each piece of data so it’s clear what the values mean. Adding these names means that structs are more flexible than tuples: you don’t have to rely on the order of the data to specify or access the values of an instance. ([Location 3950](https://readwise.io/to_kindle?action=open&asin=B0B7QTX8LL&location=3950)) - we create an instance of that struct by specifying concrete values for each of the fields. ([Location 3962](https://readwise.io/to_kindle?action=open&asin=B0B7QTX8LL&location=3962)) - To get a specific value from a struct, we use dot notation. For example, to access this user’s email address, we use user1.email. If the instance is mutable, we can change a value by using the dot notation and assigning into a particular field. ([Location 3975](https://readwise.io/to_kindle?action=open&asin=B0B7QTX8LL&location=3975)) - Note that the entire instance must be mutable; Rust doesn’t allow us to mark only certain fields as mutable. ([Location 3989](https://readwise.io/to_kindle?action=open&asin=B0B7QTX8LL&location=3989)) - Because the parameter names and the struct field names are exactly the same in Listing 5-4, we can use the field init shorthand syntax to rewrite build_user so it behaves exactly the same but doesn’t have the repetition of username and email, ([Location 4007](https://readwise.io/to_kindle?action=open&asin=B0B7QTX8LL&location=4007)) - It’s often useful to create a new instance of a struct that includes most of the values from another instance, but changes some. You can do this using struct update syntax. ([Location 4027](https://readwise.io/to_kindle?action=open&asin=B0B7QTX8LL&location=4027)) - The syntax .. specifies that the remaining fields not explicitly set should have the same value as the fields in the given instance. ([Location 4043](https://readwise.io/to_kindle?action=open&asin=B0B7QTX8LL&location=4043)) - also creates an instance in user2 that has a different value for email but has the same values for the username, active, and sign_in_count fields from user1. The ..user1 must come last to specify that any remaining fields should get their values from the corresponding fields in user1, but we can choose to specify values for as many fields as we want in any order, regardless of the order of the fields in the struct’s definition. ([Location 4054](https://readwise.io/to_kindle?action=open&asin=B0B7QTX8LL&location=4054)) - Rust also supports structs that look similar to tuples, called tuple structs. Tuple structs have the added meaning the struct name provides but don’t have names associated with their fields; rather, they just have the types of the fields. Tuple structs are useful when you want to give the whole tuple a name and make the tuple a different type from other tuples, and when naming each field as in a regular struct would be verbose or redundant. ([Location 4075](https://readwise.io/to_kindle?action=open&asin=B0B7QTX8LL&location=4075)) - Note that the black and origin values are different types because they’re instances of different tuple structs. Each struct you define is its own type, even though the fields within the struct might have the same types. ([Location 4085](https://readwise.io/to_kindle?action=open&asin=B0B7QTX8LL&location=4085)) - You can also define structs that don’t have any fields! These are called unit-like structs because they behave similarly to (), ([Location 4092](https://readwise.io/to_kindle?action=open&asin=B0B7QTX8LL&location=4092)) - Unit-like structs can be useful when you need to implement a trait on some type but don’t have any data that you want to store in the type itself. ([Location 4095](https://readwise.io/to_kindle?action=open&asin=B0B7QTX8LL&location=4095)) - It’s also possible for structs to store references to data owned by something else, but to do so requires the use of lifetimes, ([Location 4114](https://readwise.io/to_kindle?action=open&asin=B0B7QTX8LL&location=4114)) - (note that accessing fields of a borrowed struct instance does not move the field values, which is why you often see borrows of structs). ([Location 4210](https://readwise.io/to_kindle?action=open&asin=B0B7QTX8LL&location=4210)) - Putting the specifier :? inside the curly brackets tells println! we want to use an output format called Debug. The Debug trait enables us to print our struct in a way that is useful for developers so we can see its value while we’re debugging our code. ([Location 4246](https://readwise.io/to_kindle?action=open&asin=B0B7QTX8LL&location=4246)) - Rust does include functionality to print out debugging information, but we have to explicitly opt in to make that functionality available for our struct. To do that, we add the outer attribute #[derive(Debug)] just before the struct definition, ([Location 4255](https://readwise.io/to_kindle?action=open&asin=B0B7QTX8LL&location=4255)) - Another way to print out a value using the Debug format is to use the dbg! macro, which takes ownership of an expression (as opposed to println!, which takes a reference), prints the file and line number of where that dbg! macro call occurs in your code along with the resultant value of that expression, and returns ownership of the value. ([Location 4279](https://readwise.io/to_kindle?action=open&asin=B0B7QTX8LL&location=4279)) - We can put dbg! around the expression 30 * scale ❶ and, because dbg! returns ownership of the expression’s value, the width field will get the same value as if we didn’t have the dbg! call there. We don’t want dbg! to take ownership of rect1, so we use a reference to rect1 in the next call ❷. ([Location 4301](https://readwise.io/to_kindle?action=open&asin=B0B7QTX8LL&location=4301)) - In addition to the Debug trait, Rust has provided a number of traits for us to use with the derive attribute that can add useful behavior to our custom types. ([Location 4317](https://readwise.io/to_kindle?action=open&asin=B0B7QTX8LL&location=4317)) - Methods are similar to functions: we declare them with the fn keyword and a name, they can have parameters and a return value, and they contain some code that’s run when the method is called from somewhere else. Unlike functions, methods are defined within the context of a struct (or an enum or a trait object, which we cover in Chapter 6 and Chapter 17, respectively), and their first parameter is always self, which represents the instance of the struct the method is being called on. ([Location 4330](https://readwise.io/to_kindle?action=open&asin=B0B7QTX8LL&location=4330)) - ❶. Everything within this impl block will be associated with the Rectangle type. ([Location 4355](https://readwise.io/to_kindle?action=open&asin=B0B7QTX8LL&location=4355)) - we can instead use method syntax to call the area method on our Rectangle instance ([Location 4361](https://readwise.io/to_kindle?action=open&asin=B0B7QTX8LL&location=4361)) - In the signature for area, we use &self instead of rectangle: &Rectangle. The &self is actually short for self: &Self. Within an impl block, the type Self is an alias for the type that the impl block is for. Methods must have a parameter named self of type Self for their first parameter, so Rust lets you abbreviate this with only the name self in the first parameter spot. Note that we still need to use the & in front of the self shorthand to indicate that this method borrows the Self instance, just as we did in rectangle: &Rectangle. Methods can take ownership of self, borrow self immutably, as we’ve done here, or borrow self mutably, just as they can any other parameter. ([Location 4364](https://readwise.io/to_kindle?action=open&asin=B0B7QTX8LL&location=4364)) - We chose &self here for the same reason we used &Rectangle in the function version: we don’t want to take ownership, and we just want to read the data in the struct, not write to it. If we wanted to change the instance that we’ve called the method on as part of what the method does, we’d use &mut self as the first parameter. ([Location 4376](https://readwise.io/to_kindle?action=open&asin=B0B7QTX8LL&location=4376)) - Often, but not always, when we give methods with the same name as a field we want it to only return the value in the field and do nothing else. Methods like this are called getters, and Rust does not implement them automatically for struct fields as some other languages do. Getters are useful because you can make the field private but the method public, and thus enable read-only access to that field as part of the type’s public API. ([Location 4404](https://readwise.io/to_kindle?action=open&asin=B0B7QTX8LL&location=4404)) - All functions defined within an impl block are called associated functions because they’re associated with the type named after the impl. We can define associated functions that don’t have self as their first parameter (and thus are not methods) because they don’t need an instance of the type to work with. ([Location 4479](https://readwise.io/to_kindle?action=open&asin=B0B7QTX8LL&location=4479)) - Associated functions that aren’t methods are often used for constructors that will return a new instance of the struct. ([Location 4485](https://readwise.io/to_kindle?action=open&asin=B0B7QTX8LL&location=4485)) - To call this associated function, we use the :: syntax with the struct name; let sq = Rectangle::square(3); is an example. This function is namespaced by the struct: the :: syntax is used for both associated functions and namespaces created by modules. ([Location 4498](https://readwise.io/to_kindle?action=open&asin=B0B7QTX8LL&location=4498)) - Structs let you create custom types that are meaningful for your domain. By using structs, you can keep associated pieces of data connected to each other and name each piece to make your code clear. In impl blocks, you can define functions that are associated with your type, and methods are a kind of associated function that let you specify the behavior that instances of your structs have. ([Location 4517](https://readwise.io/to_kindle?action=open&asin=B0B7QTX8LL&location=4517)) - In this chapter, we’ll look at enumerations, also referred to as enums. Enums allow you to define a type by enumerating its possible variants. First we’ll define and use an enum to show how an enum can encode meaning along with data. Next, we’ll explore a particularly useful enum, called Option, which expresses that a value can be either something or nothing. Then we’ll look at how pattern matching in the match expression makes it easy to run different code for different values of an enum. Finally, we’ll cover how the if let construct is another convenient and concise idiom available to handle enums in your code. ([Location 4526](https://readwise.io/to_kindle?action=open&asin=B0B7QTX8LL&location=4526)) - Where structs give you a way of grouping together related fields and data, like a Rectangle with its width and height, enums give you a way of saying a value is one of a possible set of values. For example, we may want to say that Rectangle is one of a set of possible shapes that also includes Circle and Triangle. To do this, Rust allows us to encode these possibilities as an enum. ([Location 4534](https://readwise.io/to_kindle?action=open&asin=B0B7QTX8LL&location=4534)) - we can enumerate all possible variants, which is where enumeration gets its name. ([Location 4542](https://readwise.io/to_kindle?action=open&asin=B0B7QTX8LL&location=4542)) - Any IP address can be either a version four or a version six address, but not both at the same time. That property of IP addresses makes the enum data structure appropriate because an enum value can only be one of its variants. ([Location 4543](https://readwise.io/to_kindle?action=open&asin=B0B7QTX8LL&location=4543)) - Note that the variants of the enum are namespaced under its identifier, and we use a double colon to separate the two. This is useful because now both values IpAddrKind::V4 and IpAddrKind::V6 are of the same type: IpAddrKind. We can then, for instance, define a function that takes any IpAddrKind: ([Location 4556](https://readwise.io/to_kindle?action=open&asin=B0B7QTX8LL&location=4556)) - We attach data to each variant of the enum directly, so there is no need for an extra struct. ([Location 4596](https://readwise.io/to_kindle?action=open&asin=B0B7QTX8LL&location=4596)) - the name of each enum variant that we define also becomes a function that constructs an instance of the enum. That is, IpAddr::V4() is a function call that takes a String argument and returns an instance of the IpAddr type. ([Location 4597](https://readwise.io/to_kindle?action=open&asin=B0B7QTX8LL&location=4597)) - There’s another advantage to using an enum rather than a struct: each variant can have different types and amounts of associated data. ([Location 4601](https://readwise.io/to_kindle?action=open&asin=B0B7QTX8LL&location=4601)) - This code illustrates that you can put any kind of data inside an enum variant: strings, numeric types, or structs, for example. You can even include another enum! ([Location 4616](https://readwise.io/to_kindle?action=open&asin=B0B7QTX8LL&location=4616)) - There is one more similarity between enums and structs: just as we’re able to define methods on structs using impl, we’re also able to define methods on enums. ([Location 4645](https://readwise.io/to_kindle?action=open&asin=B0B7QTX8LL&location=4645)) - The Option type encodes the very common scenario in which a value could be something or it could be nothing. ([Location 4661](https://readwise.io/to_kindle?action=open&asin=B0B7QTX8LL&location=4661)) - Rust doesn’t have the null feature that many other languages have. ([Location 4667](https://readwise.io/to_kindle?action=open&asin=B0B7QTX8LL&location=4667)) - The Option<T> enum is so useful that it’s even included in the prelude; you don’t need to bring it into scope explicitly. Its variants are also included in the prelude: you can use Some and None directly without the Option:: prefix. The Option<T> enum is still just a regular enum, and Some(T) and None are still variants of type Option<T>. ([Location 4684](https://readwise.io/to_kindle?action=open&asin=B0B7QTX8LL&location=4684)) - When we have a None value, in some sense it means the same thing as null: we don’t have a valid value. So why is having Option<T> any better than having null? In short, because Option<T> and T (where T can be any type) are different types, the compiler won’t let us use an Option<T> value as if it were definitely a valid value. ([Location 4707](https://readwise.io/to_kindle?action=open&asin=B0B7QTX8LL&location=4707)) - In other words, you have to convert an Option<T> to a T before you can perform T operations with it. ([Location 4727](https://readwise.io/to_kindle?action=open&asin=B0B7QTX8LL&location=4727)) - In general, in order to use an Option<T> value, you want to have code that will handle each variant. You want some code that will run only when you have a Some(T) value, and this code is allowed to use the inner T. You want some other code to run only if you have a None value, and that code doesn’t have a T value available. The match expression is a control flow construct that does just this when used with enums: it will run different code depending on which variant of the enum it has, and that code can use the data inside the matching value. ([Location 4740](https://readwise.io/to_kindle?action=open&asin=B0B7QTX8LL&location=4740)) - Rust has an extremely powerful control flow construct called match that allows you to compare a value against a series of patterns and then execute code based on which pattern matches. ([Location 4747](https://readwise.io/to_kindle?action=open&asin=B0B7QTX8LL&location=4747)) - there’s a big difference: with if, the expression needs to return a Boolean value, but here it can return any type. ([Location 4770](https://readwise.io/to_kindle?action=open&asin=B0B7QTX8LL&location=4770)) - Next are the match arms. An arm has two parts: a pattern and some code. ([Location 4774](https://readwise.io/to_kindle?action=open&asin=B0B7QTX8LL&location=4774)) - When the match expression executes, it compares the resultant value against the pattern of each arm, in order. ([Location 4778](https://readwise.io/to_kindle?action=open&asin=B0B7QTX8LL&location=4778)) - If you want to run multiple lines of code in a match arm, you must use curly brackets, and the comma following the arm is then optional. ([Location 4785](https://readwise.io/to_kindle?action=open&asin=B0B7QTX8LL&location=4785)) - Another useful feature of match arms is that they can bind to the parts of the values that match the pattern. This is how we can extract values out of enum variants. ([Location 4795](https://readwise.io/to_kindle?action=open&asin=B0B7QTX8LL&location=4795)) - There’s one other aspect of match we need to discuss: the arms’ patterns must cover all possibilities. ([Location 4870](https://readwise.io/to_kindle?action=open&asin=B0B7QTX8LL&location=4870)) - Rust also has a pattern we can use when we want a catch-all but don’t want to use the value in the catch-all pattern: _ is a special pattern that matches any value and does not bind to that value. This tells Rust we aren’t going to use the value, so Rust won’t warn us about an unused variable. ([Location 4908](https://readwise.io/to_kindle?action=open&asin=B0B7QTX8LL&location=4908)) - We can express that by using the unit value ([Location 4921](https://readwise.io/to_kindle?action=open&asin=B0B7QTX8LL&location=4921)) - The if let syntax lets you combine if and let into a less verbose way to handle values that match one pattern while ignoring the rest. ([Location 4934](https://readwise.io/to_kindle?action=open&asin=B0B7QTX8LL&location=4934)) - In other words, you can think of if let as syntax sugar for a match that runs code when the value matches one pattern and then ignores all other values. ([Location 4966](https://readwise.io/to_kindle?action=open&asin=B0B7QTX8LL&location=4966)) - the module system, include: Packages A Cargo feature that lets you build, test, and share crates Crates A tree of modules that produces a library or executable Modules and use Let you control the organization, scope, and privacy of paths Paths A way of naming an item, such as a struct, function, or module ([Location 5017](https://readwise.io/to_kindle?action=open&asin=B0B7QTX8LL&location=5017)) - A crate is the smallest amount of code that the Rust compiler considers at a time. Even if you run rustc rather than cargo and pass a single source code file (as we did all the way back in “Writing and Running a Rust Program” on page 5), the compiler considers that file to be a crate. Crates can contain modules, and the modules may be defined in other files that get compiled with the crate, as we’ll see in the coming sections. ([Location 5028](https://readwise.io/to_kindle?action=open&asin=B0B7QTX8LL&location=5028)) - A crate can come in one of two forms: a binary crate or a library crate. ([Location 5033](https://readwise.io/to_kindle?action=open&asin=B0B7QTX8LL&location=5033)) - Binary crates are programs you can compile to an executable that you can run, such as a command line program or a server. ([Location 5034](https://readwise.io/to_kindle?action=open&asin=B0B7QTX8LL&location=5034)) - Library crates don’t have a main function, and they don’t compile to an executable. Instead, they define functionality intended to be shared with multiple projects. ([Location 5036](https://readwise.io/to_kindle?action=open&asin=B0B7QTX8LL&location=5036)) - The crate root is a source file that the Rust compiler starts from and makes up the root module of your crate ([Location 5041](https://readwise.io/to_kindle?action=open&asin=B0B7QTX8LL&location=5041)) - A package is a bundle of one or more crates that provides a set of functionality. ([Location 5045](https://readwise.io/to_kindle?action=open&asin=B0B7QTX8LL&location=5045)) - A crate can come in one of two forms: a binary crate or a library crate. A package can contain as many binary crates as you like, but at most only one library crate. ([Location 5049](https://readwise.io/to_kindle?action=open&asin=B0B7QTX8LL&location=5049)) - public Code within a module is private from its parent modules by default. To make a module public, declare it with pub mod instead of mod. To make items within a public module public as well, use pub before their declarations. ([Location 5093](https://readwise.io/to_kindle?action=open&asin=B0B7QTX8LL&location=5093)) - The use keyword Within a scope, the use keyword creates shortcuts to items to reduce repetition of long paths. In any scope that can refer to crate::garden::vegetables::Asparagus, you can create a shortcut with use crate::garden::vegetables::Asparagus; and from then on you only need to write Asparagus to make use of that type in the scope. ([Location 5096](https://readwise.io/to_kindle?action=open&asin=B0B7QTX8LL&location=5096)) - we’ll talk about modules and other parts of the module system, namely paths, which allow you to name items; the use keyword that brings a path into scope; and the pub keyword to make items public. We’ll also discuss the as keyword, external packages, and the glob operator. ([Location 5120](https://readwise.io/to_kindle?action=open&asin=B0B7QTX8LL&location=5120)) - Modules let us organize code within a crate for readability and easy reuse. Modules also allow us to control the privacy of items because code within a module is private by default. Private items are internal implementation details not available for outside use. ([Location 5124](https://readwise.io/to_kindle?action=open&asin=B0B7QTX8LL&location=5124)) - We define a module with the mod keyword followed by the name of the module ([Location 5146](https://readwise.io/to_kindle?action=open&asin=B0B7QTX8LL&location=5146)) - By using modules, we can group related definitions together and name why they’re related. ([Location 5151](https://readwise.io/to_kindle?action=open&asin=B0B7QTX8LL&location=5151)) - Earlier, we mentioned that src/main.rs and src/lib.rs are called crate roots. The reason for their name is that the contents of either of these two files form a module named crate at the root of the crate’s module structure, known as the module tree. ([Location 5154](https://readwise.io/to_kindle?action=open&asin=B0B7QTX8LL&location=5154)) - A path can take two forms: An absolute path is the full path starting from a crate root; for code from an external crate, the absolute path begins with the crate name, and for code from the current crate, it starts with the literal crate. A relative path starts from the current module and uses self, super, or an identifier in the current module. ([Location 5177](https://readwise.io/to_kindle?action=open&asin=B0B7QTX8LL&location=5177)) - Choosing whether to use a relative or absolute path is a decision you’ll make based on your project, and it depends on whether you’re more likely to move item definition code separately from or together with the code that uses the item. ([Location 5215](https://readwise.io/to_kindle?action=open&asin=B0B7QTX8LL&location=5215)) - Our preference in general is to specify absolute paths because it’s more likely we’ll want to move code definitions and item calls independently of each other. ([Location 5222](https://readwise.io/to_kindle?action=open&asin=B0B7QTX8LL&location=5222)) - In Rust, all items (functions, methods, structs, enums, modules, and constants) are private to parent modules by default. If you want to make an item like a function or struct private, you put it in a module. ([Location 5240](https://readwise.io/to_kindle?action=open&asin=B0B7QTX8LL&location=5240)) - Items in a parent module can’t use the private items inside child modules, but items in child modules can use the items in their ancestor modules. This is because child modules wrap and hide their implementation details, but the child modules can see the context in which they’re defined. ([Location 5242](https://readwise.io/to_kindle?action=open&asin=B0B7QTX8LL&location=5242)) - Adding the pub keyword in front of mod hosting makes the module public. With this change, if we can access front_of_house, we can access hosting. But the contents of hosting are still private; making the module public doesn’t make its contents public. ([Location 5278](https://readwise.io/to_kindle?action=open&asin=B0B7QTX8LL&location=5278)) - In the relative path, the logic is the same as the absolute path except for the first step: rather than starting from the crate root, the path starts from front_of_house. ([Location 5311](https://readwise.io/to_kindle?action=open&asin=B0B7QTX8LL&location=5311)) - If you plan on sharing your library crate so other projects can use your code, your public API is your contract with users of your crate that determines how they can interact with your code. ([Location 5317](https://readwise.io/to_kindle?action=open&asin=B0B7QTX8LL&location=5317)) - default. Typically, packages with this pattern of containing both a library and a binary crate will have just enough code in the binary crate to start an executable that calls code with the library crate. This lets other projects benefit from the most functionality that the package provides because the library crate’s code can be shared. ([Location 5325](https://readwise.io/to_kindle?action=open&asin=B0B7QTX8LL&location=5325)) - We can construct relative paths that begin in the parent module, rather than the current module or the crate root, by using super at the start of the path. This is like starting a filesystem path with the .. syntax. ([Location 5335](https://readwise.io/to_kindle?action=open&asin=B0B7QTX8LL&location=5335)) - The fix_incorrect_order function is in the back_of_house module, so we can use super to go to the parent module of back_of_house, which in this case is crate, the root. ([Location 5351](https://readwise.io/to_kindle?action=open&asin=B0B7QTX8LL&location=5351)) - We can also use pub to designate structs and enums as public, but there are a few extra details to the usage of pub with structs and enums. If we use pub before a struct definition, we make the struct public, but the struct’s fields will still be private. ([Location 5360](https://readwise.io/to_kindle?action=open&asin=B0B7QTX8LL&location=5360)) - In contrast, if we make an enum public, all of its variants are then public. We only need the pub before the enum keyword, ([Location 5394](https://readwise.io/to_kindle?action=open&asin=B0B7QTX8LL&location=5394)) - Because we made the Appetizer enum public, we can use the Soup and Salad variants in eat_at_restaurant. ([Location 5403](https://readwise.io/to_kindle?action=open&asin=B0B7QTX8LL&location=5403)) - Enums aren’t very useful unless their variants are public; it would be annoying to have to annotate all enum variants with pub in every case, so the default for enum variants is to be public. Structs are often useful without their fields being public, so struct fields follow the general rule of everything being private by default unless annotated with pub. ([Location 5406](https://readwise.io/to_kindle?action=open&asin=B0B7QTX8LL&location=5406)) - there’s a way to simplify this process: we can create a shortcut to a path with the use keyword once, and then use the shorter name everywhere else in the scope. ([Location 5418](https://readwise.io/to_kindle?action=open&asin=B0B7QTX8LL&location=5418)) - Adding use and a path in a scope is similar to creating a symbolic link in the filesystem. ([Location 5432](https://readwise.io/to_kindle?action=open&asin=B0B7QTX8LL&location=5432)) - Note that use only creates the shortcut for the particular scope in which the use occurs. ([Location 5437](https://readwise.io/to_kindle?action=open&asin=B0B7QTX8LL&location=5437)) - The compiler error shows that the shortcut no longer applies within the customer module: ([Location 5451](https://readwise.io/to_kindle?action=open&asin=B0B7QTX8LL&location=5451)) - Bringing the function’s parent module into scope with use means we have to specify the parent module when calling the function. Specifying the parent module when calling the function makes it clear that the function isn’t locally defined while still minimizing repetition of the full path. ([Location 5479](https://readwise.io/to_kindle?action=open&asin=B0B7QTX8LL&location=5479)) - On the other hand, when bringing in structs, enums, and other items with use, it’s idiomatic to specify the full path. ([Location 5483](https://readwise.io/to_kindle?action=open&asin=B0B7QTX8LL&location=5483)) - There’s no strong reason behind this idiom: it’s just the convention that has emerged, and folks have gotten used to reading and writing Rust code this way. ([Location 5492](https://readwise.io/to_kindle?action=open&asin=B0B7QTX8LL&location=5492)) - There’s another solution to the problem of bringing two types of the same name into the same scope with use: after the path, we can specify as and a new local name, or alias, for the type. ([Location 5509](https://readwise.io/to_kindle?action=open&asin=B0B7QTX8LL&location=5509)) - When we bring a name into scope with the use keyword, the name available in the new scope is private. To enable the code that calls our code to refer to that name as if it had been defined in that code’s scope, we can combine pub and use. This technique is called re-exporting because we’re bringing an item into scope but also making that item available for others to bring into their scope. ([Location 5527](https://readwise.io/to_kindle?action=open&asin=B0B7QTX8LL&location=5527)) - Before this change, external code would have to call the add_to_waitlist function by using the path restaurant::front_of_house::hosting::add_to_waitlist(). Now that this pub use has re-exported the hosting module from the root module, external code can use the path restaurant::hosting::add_to_waitlist() instead. ([Location 5543](https://readwise.io/to_kindle?action=open&asin=B0B7QTX8LL&location=5543)) - Re-exporting is useful when the internal structure of your code is different from how programmers calling your code would think about the domain. ([Location 5548](https://readwise.io/to_kindle?action=open&asin=B0B7QTX8LL&location=5548)) - Adding rand as a dependency in Cargo.toml tells Cargo to download the rand package and any dependencies from https://crates.io, and make rand available to our project. ([Location 5561](https://readwise.io/to_kindle?action=open&asin=B0B7QTX8LL&location=5561)) - If we’re using multiple items defined in the same crate or same module, listing each item on its own line can take up a lot of vertical space in our files. ([Location 5585](https://readwise.io/to_kindle?action=open&asin=B0B7QTX8LL&location=5585)) - Instead, we can use nested paths to bring the same items into scope in one line. We do this by specifying the common part of the path, followed by two colons, and then curly brackets around a list of the parts of the paths that differ, ([Location 5591](https://readwise.io/to_kindle?action=open&asin=B0B7QTX8LL&location=5591)) - If we want to bring all public items defined in a path into scope, we can specify that path followed by the * glob operator: ([Location 5621](https://readwise.io/to_kindle?action=open&asin=B0B7QTX8LL&location=5621)) - This use statement brings all public items defined in std::collections into the current scope. Be careful when using the glob operator! Glob can make it harder to tell what names are in scope and where a name used in your program was defined. ([Location 5625](https://readwise.io/to_kindle?action=open&asin=B0B7QTX8LL&location=5625)) - The glob operator is often used when testing to bring everything under test into the tests module; ([Location 5627](https://readwise.io/to_kindle?action=open&asin=B0B7QTX8LL&location=5627)) - Note that you only need to load a file using a mod declaration once in your module tree. Once the compiler knows the file is part of the project (and knows where in the module tree the code resides because of where you’ve put the mod statement), other files in your project should refer to the loaded file’s code using a path to where it was declared, as covered in “Paths for Referring to an Item in the Module Tree” on page 125. In other words, mod is not an “include” operation that you may have seen in other programming languages. ([Location 5659](https://readwise.io/to_kindle?action=open&asin=B0B7QTX8LL&location=5659)) - If we instead put hosting.rs in the src directory, the compiler would expect the hosting.rs code to be in a hosting module declared in the crate root, and not declared as a child of the front_of_house module. ([Location 5680](https://readwise.io/to_kindle?action=open&asin=B0B7QTX8LL&location=5680)) - Rust’s standard library includes a number of very useful data structures called collections. Most other data types represent one specific value, but collections can contain multiple values. Unlike the built-in array and tuple types, the data that these collections point to is stored on the heap, which means the amount of data does not need to be known at compile time and can grow or shrink as the program runs. ([Location 5717](https://readwise.io/to_kindle?action=open&asin=B0B7QTX8LL&location=5717)) - A vector allows you to store a variable number of values next to each other. ([Location 5722](https://readwise.io/to_kindle?action=open&asin=B0B7QTX8LL&location=5722)) - A string is a collection of characters. We’ve mentioned the String type previously, but in this chapter we’ll talk about it in depth. ([Location 5723](https://readwise.io/to_kindle?action=open&asin=B0B7QTX8LL&location=5723)) - A hash map allows you to associate a value with a specific key. It’s a particular implementation of the more general data structure called a map. ([Location 5725](https://readwise.io/to_kindle?action=open&asin=B0B7QTX8LL&location=5725)) - The first collection type we’ll look at is Vec<T>, also known as a vector. Vectors allow you to store more than one value in a single data structure that puts all the values next to each other in memory. Vectors can only store values of the same type. They are useful when you have a list of items, such as the lines of text in a file or the prices of items in a shopping cart. ([Location 5732](https://readwise.io/to_kindle?action=open&asin=B0B7QTX8LL&location=5732)) - Vectors are implemented using generics; ([Location 5744](https://readwise.io/to_kindle?action=open&asin=B0B7QTX8LL&location=5744)) - now, know that the Vec<T> type provided by the standard library can hold any type. When we create a vector to hold a specific type, we can specify the type within angle brackets. ([Location 5745](https://readwise.io/to_kindle?action=open&asin=B0B7QTX8LL&location=5745)) - More often, you’ll create a Vec<T> with initial values and Rust will infer the type of value you want to store, so you rarely need to do this type annotation. Rust conveniently provides the vec! macro, which will create a new vector that holds the values you give it. ([Location 5749](https://readwise.io/to_kindle?action=open&asin=B0B7QTX8LL&location=5749)) - To create a vector and then add elements to it, we can use the push method, ([Location 5763](https://readwise.io/to_kindle?action=open&asin=B0B7QTX8LL&location=5763)) - As with any variable, if we want to be able to change its value, we need to make it mutable using the mut keyword, ([Location 5769](https://readwise.io/to_kindle?action=open&asin=B0B7QTX8LL&location=5769)) - There are two ways to reference a value stored in a vector: via indexing or by using the get method. ([Location 5774](https://readwise.io/to_kindle?action=open&asin=B0B7QTX8LL&location=5774)) - We use the index value of 2 to get the third element ❶ because vectors are indexed by number, starting at zero. ([Location 5785](https://readwise.io/to_kindle?action=open&asin=B0B7QTX8LL&location=5785)) - the first [] method will cause the program to panic because it references a nonexistent element. This method is best used when you want your program to crash if there’s an attempt to access an element past the end of the vector. ([Location 5798](https://readwise.io/to_kindle?action=open&asin=B0B7QTX8LL&location=5798)) - When the get method is passed an index that is outside the vector, it returns None without panicking. ([Location 5801](https://readwise.io/to_kindle?action=open&asin=B0B7QTX8LL&location=5801)) - Your code will then have logic to handle having either Some(&element) or None, as discussed in Chapter 6. For example, the index could be coming from a person entering a number. If they accidentally enter a number that’s too large and the program gets a None value, you could tell the user how many items are in the current vector and give them another chance to enter a valid value. That would be more user-friendly than crashing the program due to a typo! ([Location 5803](https://readwise.io/to_kindle?action=open&asin=B0B7QTX8LL&location=5803)) - where we hold an immutable reference to the first element in a vector and try to add an element to the end. This program won’t work if we also try to refer to that element later in the function. ([Location 5811](https://readwise.io/to_kindle?action=open&asin=B0B7QTX8LL&location=5811)) - why should a reference to the first element care about changes at the end of the vector? This error is due to the way vectors work: because vectors put the values next to each other in memory, adding a new element onto the end of the vector might require allocating new memory and copying the old elements to the new space, if there isn’t enough room to put all the elements next to each other where the vector is currently stored. In that case, the reference to the first element would be pointing to deallocated memory. The borrowing rules prevent programs from ending up in that situation. ([Location 5824](https://readwise.io/to_kindle?action=open&asin=B0B7QTX8LL&location=5824)) - To change the value that the mutable reference refers to, we have to use the * dereference operator to get to the value in i before we can use the += operator. ([Location 5850](https://readwise.io/to_kindle?action=open&asin=B0B7QTX8LL&location=5850)) - Iterating over a vector, whether immutably or mutably, is safe because of the borrow checker’s rules. If we attempted to insert or remove items in the for loop bodies in Listing 8-7 and Listing 8-8, we would get a compiler error similar to the one we got with the code in Listing 8-6. The reference to the vector that the for loop holds prevents simultaneous modification of the whole vector. ([Location 5854](https://readwise.io/to_kindle?action=open&asin=B0B7QTX8LL&location=5854)) - Vectors can only store values that are of the same type. This can be inconvenient; there are definitely use cases for needing to store a list of items of different types. Fortunately, the variants of an enum are defined under the same enum type, so when we need one type to represent elements of different types, we can define and use an enum! ([Location 5860](https://readwise.io/to_kindle?action=open&asin=B0B7QTX8LL&location=5860)) - types, and all the enum variants will be considered the same type: that of the enum. ([Location 5865](https://readwise.io/to_kindle?action=open&asin=B0B7QTX8LL&location=5865)) - Rust needs to know what types will be in the vector at compile time so it knows exactly how much memory on the heap will be needed to store each element. We must also be explicit about what types are allowed in this vector. If Rust allowed a vector to hold any type, there would be a chance that one or more of the types would cause errors with the operations performed on the elements of the vector. Using an enum plus a match expression means that Rust will ensure at compile time that every possible case is handled, ([Location 5873](https://readwise.io/to_kindle?action=open&asin=B0B7QTX8LL&location=5873)) - If you don’t know the exhaustive set of types a program will get at runtime to store in a vector, the enum technique won’t work. Instead, you can use a trait object, ([Location 5877](https://readwise.io/to_kindle?action=open&asin=B0B7QTX8LL&location=5877)) - string. Rust has only one string type in the core language, which is the string slice str that is usually seen in its borrowed form &str. ([Location 5906](https://readwise.io/to_kindle?action=open&asin=B0B7QTX8LL&location=5906)) - about string slices, which are references to some UTF-8 encoded string data stored elsewhere. String literals, for example, are stored in the program’s binary and are therefore string slices. ([Location 5908](https://readwise.io/to_kindle?action=open&asin=B0B7QTX8LL&location=5908)) - The String type, which is provided by Rust’s standard library rather than coded into the core language, is a growable, mutable, owned, UTF-8 encoded string type. When Rustaceans refer to “strings” in Rust, they might be referring to either the String or the string slice &str types, ([Location 5910](https://readwise.io/to_kindle?action=open&asin=B0B7QTX8LL&location=5910)) - Many of the same operations available with Vec<T> are available with String as well because String is actually implemented as a wrapper around a vector of bytes with some extra guarantees, restrictions, and capabilities. ([Location 5917](https://readwise.io/to_kindle?action=open&asin=B0B7QTX8LL&location=5917)) - This line creates a new, empty string called s, into which we can then load data. Often, we’ll have some initial data with which we want to start the string. For that, we use the to_string method, which is available on any type that implements the Display trait, as string literals do. ([Location 5926](https://readwise.io/to_kindle?action=open&asin=B0B7QTX8LL&location=5926)) - We can also use the function String::from to create a String from a string literal. ([Location 5937](https://readwise.io/to_kindle?action=open&asin=B0B7QTX8LL&location=5937)) - A String can grow in size and its contents can change, just like the contents of a Vec<T>, if you push more data into it. In addition, you can conveniently use the + operator or the format! macro to concatenate String values. ([Location 5958](https://readwise.io/to_kindle?action=open&asin=B0B7QTX8LL&location=5958)) - We can grow a String by using the push_str method to append a string slice, ([Location 5964](https://readwise.io/to_kindle?action=open&asin=B0B7QTX8LL&location=5964)) - If the push_str method took ownership of s2, we wouldn’t be able to print its value on the last line. However, this code works as we’d expect! ([Location 5979](https://readwise.io/to_kindle?action=open&asin=B0B7QTX8LL&location=5979)) - The string s3 will contain Hello, world!. The reason s1 is no longer valid after the addition, and the reason we used a reference to s2, has to do with the signature of the method that’s called when we use the + operator. The + operator uses the add method, whose signature looks something like this: ([Location 5999](https://readwise.io/to_kindle?action=open&asin=B0B7QTX8LL&location=5999)) - First, s2 has an &, meaning that we’re adding a reference of the second string to the first string. This is because of the s parameter in the add function: we can only add a &str to a String; we can’t add two String values together. But wait—the type of &s2 is &String, not &str, as specified in the second parameter to add. ([Location 6010](https://readwise.io/to_kindle?action=open&asin=B0B7QTX8LL&location=6010)) - The reason we’re able to use &s2 in the call to add is that the compiler can coerce the &String argument into a &str. When we call the add method, Rust uses a deref coercion, which here turns &s2 into &s2[..]. ([Location 6017](https://readwise.io/to_kindle?action=open&asin=B0B7QTX8LL&location=6017)) - Second, we can see in the signature that add takes ownership of self because self does not have an &. This means s1 in Listing 8-18 will be moved into the add call and will no longer be valid after that. ([Location 6025](https://readwise.io/to_kindle?action=open&asin=B0B7QTX8LL&location=6025)) - The error and the note tell the story: Rust strings don’t support indexing. ([Location 6061](https://readwise.io/to_kindle?action=open&asin=B0B7QTX8LL&location=6061)) - A String is a wrapper over a Vec<u8>. ([Location 6064](https://readwise.io/to_kindle?action=open&asin=B0B7QTX8LL&location=6064)) - storage. Therefore, an index into the string’s bytes will not always correlate to a valid Unicode scalar value. ([Location 6076](https://readwise.io/to_kindle?action=open&asin=B0B7QTX8LL&location=6076)) - Another point about UTF-8 is that there are actually three relevant ways to look at strings from Rust’s perspective: as bytes, scalar values, and grapheme clusters (the closest thing to what we would call letters). ([Location 6091](https://readwise.io/to_kindle?action=open&asin=B0B7QTX8LL&location=6091)) - Indexing into a string is often a bad idea because it’s not clear what the return type of the string-indexing operation should be: a byte value, a character, a grapheme cluster, or a string slice. If you really need to use indices to create string slices, therefore, Rust asks you to be more specific. ([Location 6112](https://readwise.io/to_kindle?action=open&asin=B0B7QTX8LL&location=6112)) - The best way to operate on pieces of strings is to be explicit about whether you want characters or bytes. For individual Unicode scalar values, use the chars method. ([Location 6129](https://readwise.io/to_kindle?action=open&asin=B0B7QTX8LL&location=6129)) - Rust has chosen to make the correct handling of String data the default behavior for all Rust programs, which means programmers have to put more thought into handling UTF-8 data up front. This trade-off exposes more of the complexity of strings than is apparent in other programming languages, but it prevents you from having to handle errors involving non-ASCII characters later in your development life cycle. The good news is that the standard library offers a lot of functionality built off the String and &str types to help handle these complex situations correctly. Be sure to check out the documentation for useful methods like contains for searching in a string and replace for substituting parts of a string with another string. ([Location 6148](https://readwise.io/to_kindle?action=open&asin=B0B7QTX8LL&location=6148)) - The last of our common collections is the hash map. The type HashMap<K, V> stores a mapping of keys of type K to values of type V using a hashing function, which determines how it places these keys and values into memory. Many programming languages support this kind of data structure, but they often use a different name, such as hash, map, object, hash table, dictionary, or associative array, just to name a few. ([Location 6158](https://readwise.io/to_kindle?action=open&asin=B0B7QTX8LL&location=6158)) - Hash maps are useful when you want to look up data not by using an index, as you can with vectors, but by using a key that can be of any type. ([Location 6165](https://readwise.io/to_kindle?action=open&asin=B0B7QTX8LL&location=6165)) - The get method returns an Option<&V>; if there’s no value for that key in the hash map, get will return None. This program handles the Option by calling copied to get an Option<i32> rather than an Option<&i32>, then unwrap_or to set score to zero if scores doesn’t have an entry for the key. ([Location 6197](https://readwise.io/to_kindle?action=open&asin=B0B7QTX8LL&location=6197)) - For types that implement the Copy trait, like i32, the values are copied into the hash map. For owned values like String, the values will be moved and the hash map will be the owner of those values, ([Location 6214](https://readwise.io/to_kindle?action=open&asin=B0B7QTX8LL&location=6214)) - We aren’t able to use the variables field_name and field_value after they’ve been moved into the hash map with the call to insert. ([Location 6223](https://readwise.io/to_kindle?action=open&asin=B0B7QTX8LL&location=6223)) - Although the number of key and value pairs is growable, each unique key can only have one value associated with it at a time (but not vice versa: for example, both the Blue team and the Yellow team could have the value 10 stored in the scores hash map). ([Location 6229](https://readwise.io/to_kindle?action=open&asin=B0B7QTX8LL&location=6229)) - If we insert a key and a value into a hash map and then insert that same key with a different value, the value associated with that key will be replaced. ([Location 6237](https://readwise.io/to_kindle?action=open&asin=B0B7QTX8LL&location=6237)) - It’s common to check whether a particular key already exists in the hash map with a value and then to take the following actions: if the key does exist in the hash map, the existing value should remain the way it is; if the key doesn’t exist, insert it and a value for it. Hash maps have a special API for this called entry that takes the key you want to check as a parameter. ([Location 6249](https://readwise.io/to_kindle?action=open&asin=B0B7QTX8LL&location=6249)) - The or_insert method on Entry is defined to return a mutable reference to the value for the corresponding Entry key if that key exists, and if not, it inserts the parameter as the new value for this key and returns a mutable reference to the new value. ([Location 6262](https://readwise.io/to_kindle?action=open&asin=B0B7QTX8LL&location=6262)) - Another common use case for hash maps is to look up a key’s value and then update it based on the old value. ([Location 6272](https://readwise.io/to_kindle?action=open&asin=B0B7QTX8LL&location=6272)) - The split_whitespace method returns an iterator over subslices, separated by whitespace, of the value in text. The or_insert method returns a mutable reference (&mut V) to the value for the specified key. Here, we store that mutable reference in the count variable, so in order to assign to that value, we must first dereference count using the asterisk (*). The mutable reference goes out of scope at the end of the for loop, so all of these changes are safe and allowed by the borrowing rules. ([Location 6285](https://readwise.io/to_kindle?action=open&asin=B0B7QTX8LL&location=6285)) - By default, HashMap uses a hashing function called SipHash that can provide resistance to denial-of-service (DoS) attacks involving hash tables. This is not the fastest hashing algorithm available, but the trade-off for better security that comes with the drop in performance is worth it. If you profile your code and find that the default hash function is too slow for your purposes, you can switch to another function by specifying a different hasher. A hasher is a type that implements the BuildHasher trait. ([Location 6293](https://readwise.io/to_kindle?action=open&asin=B0B7QTX8LL&location=6293)) - Rust groups errors into two major categories: recoverable and unrecoverable errors. For a recoverable error, such as a file not found error, we most likely just want to report the problem to the user and retry the operation. Unrecoverable errors are always symptoms of bugs, such as trying to access a location beyond the end of an array, and so we want to immediately stop the program. ([Location 6322](https://readwise.io/to_kindle?action=open&asin=B0B7QTX8LL&location=6322)) - Most languages don’t distinguish between these two kinds of errors and handle both in the same way, using mechanisms such as exceptions. Rust doesn’t have exceptions. Instead, it has the type Result<T, E> for recoverable errors and the panic! macro that stops execution when the program encounters an unrecoverable error. This chapter covers calling panic! first and then talks about returning Result<T, E> values. Additionally, we’ll explore considerations when deciding whether to try to recover from an error or to stop execution. ([Location 6326](https://readwise.io/to_kindle?action=open&asin=B0B7QTX8LL&location=6326)) - By default, when a panic occurs the program starts unwinding, which means Rust walks back up the stack and cleans up the data from each function it encounters. However, walking back and cleaning up is a lot of work. Rust, therefore, allows you to choose the alternative of immediately aborting, which ends the program without cleaning up. Memory that the program was using will then need to be cleaned up by the operating system. If in your project you need to make the resultant binary as small as possible, you can switch from unwinding to aborting upon a panic by adding panic = 'abort' to the appropriate [profile] sections in your Cargo.toml file. For example, if you want to abort on panic in release mode, add this: ([Location 6341](https://readwise.io/to_kindle?action=open&asin=B0B7QTX8LL&location=6341)) - In this case, the line indicated is part of our code, and if we go to that line, we see the panic! macro call. In other cases, the panic! call might be in code that our code calls, and the filename and line number reported by the error message will be someone else’s code where the panic! macro is called, not the line of our code that eventually led to the panic! call. ([Location 6361](https://readwise.io/to_kindle?action=open&asin=B0B7QTX8LL&location=6361)) - We can use the backtrace of the functions the panic! call came from to figure out the part of our code that is causing the problem. ([Location 6365](https://readwise.io/to_kindle?action=open&asin=B0B7QTX8LL&location=6365)) - In C, attempting to read beyond the end of a data structure is undefined behavior. You might get whatever is at the location in memory that would correspond to that element in the data structure, even though the memory doesn’t belong to that structure. This is called a buffer overread and can lead to security vulnerabilities if an attacker is able to manipulate the index in such a way as to read data they shouldn’t be allowed to that is stored after the data structure. ([Location 6379](https://readwise.io/to_kindle?action=open&asin=B0B7QTX8LL&location=6379)) - A backtrace is a list of all the functions that have been called to get to this point. Backtraces in Rust work as they do in other languages: the key to reading the backtrace is to start from the top and read until you see files you wrote. ([Location 6391](https://readwise.io/to_kindle?action=open&asin=B0B7QTX8LL&location=6391)) - Debug symbols are enabled by default when using cargo build or cargo run without the --release flag, as we have here. ([Location 6415](https://readwise.io/to_kindle?action=open&asin=B0B7QTX8LL&location=6415)) - the Result enum is defined as having two variants, Ok and Err, ([Location 6433](https://readwise.io/to_kindle?action=open&asin=B0B7QTX8LL&location=6433)) - T represents the type of the value that will be returned in a success case within the Ok variant, and E represents the type of the error that will be returned in a failure case within the Err variant. ([Location 6439](https://readwise.io/to_kindle?action=open&asin=B0B7QTX8LL&location=6439)) - and look up the unwrap_or_else method in the standard library documentation. ([Location 6548](https://readwise.io/to_kindle?action=open&asin=B0B7QTX8LL&location=6548)) - Using match works well enough, but it can be a bit verbose and doesn’t always communicate intent well. The Result<T, E> type has many helper methods defined on it to do various, more specific tasks. The unwrap method is a shortcut method implemented just like the match expression we wrote in Listing 9-4. If the Result value is the Ok variant, unwrap will return the value inside the Ok. If the Result is the Err variant, unwrap will call the panic! macro for us. ([Location 6551](https://readwise.io/to_kindle?action=open&asin=B0B7QTX8LL&location=6551)) - In production-quality code, most Rustaceans choose expect rather than unwrap and give more context about why the operation is expected to always succeed. That way, if your assumptions are ever proven wrong, you have more information to use in debugging. ([Location 6584](https://readwise.io/to_kindle?action=open&asin=B0B7QTX8LL&location=6584)) - When a function’s implementation calls something that might fail, instead of handling the error within the function itself, you can return the error to the calling code so that it can decide what to do. This is known as propagating the error and gives more control to the calling code, where there might be more information or logic that dictates how the error should be handled than what you have available in the context of your code. ([Location 6588](https://readwise.io/to_kindle?action=open&asin=B0B7QTX8LL&location=6588)) - The ? placed after a Result value is defined to work in almost the same way as the match expressions we defined to handle the Result values in Listing 9-6. If the value of the Result is an Ok, the value inside the Ok will get returned from this expression, and the program will continue. If the value is an Err, the Err will be returned from the whole function as if we had used the return keyword so the error value gets propagated to the calling code. ([Location 6664](https://readwise.io/to_kindle?action=open&asin=B0B7QTX8LL&location=6664)) - There is a difference between what the match expression from Listing 9-6 does and what the ? operator does: error values that have the ? operator called on them go through the from function, defined in the From trait in the standard library, which is used to convert values from one type into another. When the ? operator calls the from function, the error type received is converted into the error type defined in the return type of the current function. This is useful when a function returns one error type to represent all the ways a function might fail, even if parts might fail for many different reasons. ([Location 6671](https://readwise.io/to_kindle?action=open&asin=B0B7QTX8LL&location=6671)) - The ? operator can only be used in functions whose return type is compatible with the value the ? is used on. This is because the ? operator is defined to perform an early return of a value out of the function, in the same manner as the match expression we defined in Listing 9-6. In Listing 9-6, the match was using a Result value, and the early return arm returned an Err(e) value. The return type of the function has to be a Result so that it’s compatible with this return. ([Location 6725](https://readwise.io/to_kindle?action=open&asin=B0B7QTX8LL&location=6725)) - The error message also mentioned that ? can be used with Option<T> values as well. As with using ? on Result, you can only use ? on Option in a function that returns an Option. The behavior of the ? operator when called on an Option<T> is similar to its behavior when called on a Result<T, E>: if the value is None, the None will be returned early from the function at that point. If the value is Some, the value inside the Some is the resultant value of the expression, and the function continues. ([Location 6760](https://readwise.io/to_kindle?action=open&asin=B0B7QTX8LL&location=6760)) - Note that you can use the ? operator on a Result in a function that returns Result, and you can use the ? operator on an Option in a function that returns Option, but you can’t mix and match. The ? operator won’t automatically convert a Result to an Option or vice versa; in those cases, you can use methods like the ok method on Result or the ok_or method on Option to do the conversion explicitly. ([Location 6794](https://readwise.io/to_kindle?action=open&asin=B0B7QTX8LL&location=6794)) - So far, all the main functions we’ve used return (). The main function is special because it’s the entry point and exit point of an executable program, and there are restrictions on what its return type can be for the program to behave as expected. Luckily, main can also return a Result<(), E>. Listing 9-12 has the code from Listing 9-10, but we’ve changed the return type of main to be Result<(), Box<dyn Error>> and added a return value Ok(()) to the end. This code will now compile. ([Location 6802](https://readwise.io/to_kindle?action=open&asin=B0B7QTX8LL&location=6802)) - The Box<dyn Error> type is a trait object, which we’ll talk about in “Using Trait Objects That Allow for Values of Different Types” on page 379. For now, you can read Box<dyn Error> to mean “any kind of error.” Using ? on a Result value in a main function with the error type Box<dyn Error> is allowed because it allows any Err value to be returned early. ([Location 6818](https://readwise.io/to_kindle?action=open&asin=B0B7QTX8LL&location=6818)) - When a main function returns a Result<(), E>, the executable will exit with a value of 0 if main returns Ok(()) and will exit with a nonzero value if main returns an Err value. ([Location 6828](https://readwise.io/to_kindle?action=open&asin=B0B7QTX8LL&location=6828)) - returning Result is a good default choice when you’re defining a function that might fail. ([Location 6849](https://readwise.io/to_kindle?action=open&asin=B0B7QTX8LL&location=6849)) - the unwrap and expect methods are very handy when prototyping, before you’re ready to decide how to handle errors. ([Location 6858](https://readwise.io/to_kindle?action=open&asin=B0B7QTX8LL&location=6858)) - Instead, we can make a new type and put the validations in a function to create an instance of the type rather than repeating the validations everywhere. ([Location 6946](https://readwise.io/to_kindle?action=open&asin=B0B7QTX8LL&location=6946)) - Next, we implement a method named value that borrows self, doesn’t have any other parameters, and returns an i32 ❻. This kind of method is sometimes called a getter because its purpose is to get some data from its fields and return it. ([Location 6980](https://readwise.io/to_kindle?action=open&asin=B0B7QTX8LL&location=6980)) - Every programming language has tools for effectively handling the duplication of concepts. In Rust, one such tool is generics: abstract stand-ins for concrete types or other properties. We can express the behavior of generics or how they relate to other generics without knowing what will be in their place when compiling and running the code. ([Location 7007](https://readwise.io/to_kindle?action=open&asin=B0B7QTX8LL&location=7007)) - Functions can take parameters of some generic type, instead of a concrete type like i32 or String, in the same way they take parameters with unknown values to run the same code on multiple concrete values. In fact, we’ve already used generics in Chapter 6 with Option<T>, in Chapter 8 with Vec<T> and HashMap<K, V>, and in Chapter 9 with Result<T, E>. ([Location 7010](https://readwise.io/to_kindle?action=open&asin=B0B7QTX8LL&location=7010)) - Then you’ll learn how to use traits to define behavior in a generic way. ([Location 7020](https://readwise.io/to_kindle?action=open&asin=B0B7QTX8LL&location=7020)) - lifetimes: a variety of generics that give the compiler information about how references relate to each other. ([Location 7023](https://readwise.io/to_kindle?action=open&asin=B0B7QTX8LL&location=7023)) - Next, we’ll use these same steps with generics to reduce code duplication. In the same way that the function body can operate on an abstract list instead of specific values, generics allow code to operate on abstract types. ([Location 7091](https://readwise.io/to_kindle?action=open&asin=B0B7QTX8LL&location=7091)) - We use generics to create definitions for items like function signatures or structs, which we can then use with many different concrete data types. ([Location 7098](https://readwise.io/to_kindle?action=open&asin=B0B7QTX8LL&location=7098)) - When defining a function that uses generics, we place the generics in the signature of the function where we would usually specify the data types of the parameters and return value. ([Location 7101](https://readwise.io/to_kindle?action=open&asin=B0B7QTX8LL&location=7101)) - To parameterize the types in a new single function, we need to name the type parameter, just as we do for the value parameters to a function. You can use any identifier as a type parameter name. But we’ll use T because, by convention, type parameter names in Rust are short, often just one letter, and Rust’s type-naming convention is CamelCase. Short for type, T is the default choice of most Rust programmers. ([Location 7123](https://readwise.io/to_kindle?action=open&asin=B0B7QTX8LL&location=7123)) - section. For now, know that this error states that the body of largest won’t work for all possible types that T could be. Because we want to compare values of type T in the body, we can only use types whose values can be ordered. ([Location 7164](https://readwise.io/to_kindle?action=open&asin=B0B7QTX8LL&location=7164)) - We can also define structs to use a generic type parameter in one or more fields using the <> syntax. ([Location 7173](https://readwise.io/to_kindle?action=open&asin=B0B7QTX8LL&location=7173)) - To define a Point struct where x and y are both generics but could have different types, we can use multiple generic type parameters. For example, in Listing 10-8, we change the definition of Point to be generic over types T and U where x is of type T and y is of type U. ([Location 7211](https://readwise.io/to_kindle?action=open&asin=B0B7QTX8LL&location=7211)) - Enums can use multiple generic types as well. ([Location 7239](https://readwise.io/to_kindle?action=open&asin=B0B7QTX8LL&location=7239)) - Note that we have to declare T just after impl so we can use T to specify that we’re implementing methods on the type Point<T>. By declaring T as a generic type after impl, Rust can identify that the type in the angle brackets in Point is a generic type rather than a concrete type. ([Location 7271](https://readwise.io/to_kindle?action=open&asin=B0B7QTX8LL&location=7271)) - We can also specify constraints on generic types when defining methods on the type. We could, for example, implement methods only on Point<f32> instances rather than on Point<T> instances with any generic type. ([Location 7279](https://readwise.io/to_kindle?action=open&asin=B0B7QTX8LL&location=7279)) - This code means the type Point<f32> will have a distance_from_origin method; other instances of Point<T> where T is not of type f32 will not have this method defined. ([Location 7290](https://readwise.io/to_kindle?action=open&asin=B0B7QTX8LL&location=7290)) - You might be wondering whether there is a runtime cost when using generic type parameters. The good news is that using generic types won’t make your program run any slower than it would with concrete types. Rust accomplishes this by performing monomorphization of the code using generics at compile time. Monomorphization is the process of turning generic code into specific code by filling in the concrete types that are used when compiled. ([Location 7337](https://readwise.io/to_kindle?action=open&asin=B0B7QTX8LL&location=7337)) - A trait defines the functionality a particular type has and can share with other types. We can use traits to define shared behavior in an abstract way. We can use trait bounds to specify that a generic type can be any type that has certain behavior. ([Location 7364](https://readwise.io/to_kindle?action=open&asin=B0B7QTX8LL&location=7364)) - A type’s behavior consists of the methods we can call on that type. Different types share the same behavior if we can call the same methods on all of those types. Trait definitions are a way to group method signatures together to define a set of behaviors necessary to accomplish some purpose. ([Location 7372](https://readwise.io/to_kindle?action=open&asin=B0B7QTX8LL&location=7372)) - A trait can have multiple methods in its body: the method signatures are listed one per line, and each line ends in a semicolon. ([Location 7397](https://readwise.io/to_kindle?action=open&asin=B0B7QTX8LL&location=7397)) - Implementing a trait on a type is similar to implementing regular methods. The difference is that after impl, we put the trait name we want to implement, then use the for keyword, and then specify the name of the type we want to implement the trait for. ([Location 7419](https://readwise.io/to_kindle?action=open&asin=B0B7QTX8LL&location=7419)) - But we can’t implement external traits on external types. For example, we can’t implement the Display trait on Vec<T> within our aggregator crate because Display and Vec<T> are both defined in the standard library and aren’t local to our aggregator crate. This restriction is part of a property called coherence, and more specifically the orphan rule, so named because the parent type is not present. This rule ensures that other people’s code can’t break your code and vice versa. Without the rule, two crates could implement the same trait for the same type, and Rust wouldn’t know which implementation to use. ([Location 7445](https://readwise.io/to_kindle?action=open&asin=B0B7QTX8LL&location=7445)) - Sometimes it’s useful to have default behavior for some or all of the methods in a trait instead of requiring implementations for all methods on every type. Then, as we implement the trait on a particular type, we can keep or override each method’s default behavior. ([Location 7454](https://readwise.io/to_kindle?action=open&asin=B0B7QTX8LL&location=7454)) - Now that you know how to define and implement traits, we can explore how to use traits to define functions that accept many different types. ([Location 7511](https://readwise.io/to_kindle?action=open&asin=B0B7QTX8LL&location=7511)) - Instead of a concrete type for the item parameter, we specify the impl keyword and the trait name. This parameter accepts any type that implements the specified trait. In the body of notify, we can call any methods on item that come from the Summary trait, such as summarize. ([Location 7519](https://readwise.io/to_kindle?action=open&asin=B0B7QTX8LL&location=7519)) - The impl Trait syntax works for straightforward cases but is actually syntax sugar for a longer form known as a trait bound; ([Location 7528](https://readwise.io/to_kindle?action=open&asin=B0B7QTX8LL&location=7528)) - Using impl Trait is appropriate if we want this function to allow item1 and item2 to have different types (as long as both types implement Summary). ([Location 7540](https://readwise.io/to_kindle?action=open&asin=B0B7QTX8LL&location=7540)) - The ability to specify a return type only by the trait it implements is especially useful in the context of closures and iterators, ([Location 7587](https://readwise.io/to_kindle?action=open&asin=B0B7QTX8LL&location=7587)) - Closures and iterators create types that only the compiler knows or types that are very long to specify. The impl Trait syntax lets you concisely specify that a function returns some type that implements the Iterator trait without needing to write out a very long type. ([Location 7588](https://readwise.io/to_kindle?action=open&asin=B0B7QTX8LL&location=7588)) - you can only use impl Trait if you’re returning a single type. ([Location 7591](https://readwise.io/to_kindle?action=open&asin=B0B7QTX8LL&location=7591)) - By using a trait bound with an impl block that uses generic type parameters, we can implement methods conditionally for types that implement the specified traits. ([Location 7612](https://readwise.io/to_kindle?action=open&asin=B0B7QTX8LL&location=7612)) - We can also conditionally implement a trait for any type that implements another trait. Implementations of a trait on any type that satisfies the trait bounds are called blanket implementations and are used extensively in the Rust standard library. ([Location 7633](https://readwise.io/to_kindle?action=open&asin=B0B7QTX8LL&location=7633)) - Lifetimes are another kind of generic that we’ve already been using. Rather than ensuring that a type has the behavior we want, lifetimes ensure that references are valid as long as we need them to be. ([Location 7654](https://readwise.io/to_kindle?action=open&asin=B0B7QTX8LL&location=7654)) - lifetime, which is the scope for which that reference is valid. Most of the time, lifetimes are implicit and inferred, just like most of the time, types are inferred. ([Location 7657](https://readwise.io/to_kindle?action=open&asin=B0B7QTX8LL&location=7657)) - The main aim of lifetimes is to prevent dangling references, which cause a program to reference data other than the data it’s intended to reference. ([Location 7665](https://readwise.io/to_kindle?action=open&asin=B0B7QTX8LL&location=7665)) - 7. But r is still valid for the outer scope; because its scope is larger, we say that it “lives longer.” If Rust allowed this code to work, r would be referencing memory that was deallocated when x went out of scope, and anything we tried to do with r wouldn’t work correctly. ([Location 7694](https://readwise.io/to_kindle?action=open&asin=B0B7QTX8LL&location=7694)) - Here, x has the lifetime 'b, which in this case is larger than 'a. This means r can reference x because Rust knows that the reference in r will always be valid while x is valid. ([Location 7732](https://readwise.io/to_kindle?action=open&asin=B0B7QTX8LL&location=7732)) - The help text reveals that the return type needs a generic lifetime parameter on it because Rust can’t tell whether the reference being returned refers to x or y. Actually, we don’t know either, because the if block in the body of this function returns a reference to x and the else block returns a reference to y! ([Location 7770](https://readwise.io/to_kindle?action=open&asin=B0B7QTX8LL&location=7770)) - Lifetime annotations don’t change how long any of the references live. Rather, they describe the relationships of the lifetimes of multiple references to each other without affecting the lifetimes. Just as functions can accept any type when the signature specifies a generic type parameter, functions can accept references with any lifetime by specifying a generic lifetime parameter. ([Location 7783](https://readwise.io/to_kindle?action=open&asin=B0B7QTX8LL&location=7783)) - To use lifetime annotations in function signatures, we need to declare the generic lifetime parameters inside angle brackets between the function name and the parameter list, just as we did with generic type parameters. ([Location 7800](https://readwise.io/to_kindle?action=open&asin=B0B7QTX8LL&location=7800)) - We want the signature to express the following constraint: the returned reference will be valid as long as both the parameters are valid. This is the relationship between lifetimes of the parameters and the return value. We’ll name the lifetime 'a and then add it to each reference, ([Location 7803](https://readwise.io/to_kindle?action=open&asin=B0B7QTX8LL&location=7803)) - The function signature now tells Rust that for some lifetime 'a, the function takes two parameters, both of which are string slices that live at least as long as lifetime 'a. The function signature also tells Rust that the string slice returned from the function will live at least as long as lifetime 'a. In practice, it means that the lifetime of the reference returned by the longest function is the same as the smaller of the lifetimes of the values referred to by the function arguments. These relationships are what we want Rust to use when analyzing this code. ([Location 7817](https://readwise.io/to_kindle?action=open&asin=B0B7QTX8LL&location=7817)) - When annotating lifetimes in functions, the annotations go in the function signature, not in the function body. The lifetime annotations become part of the contract of the function, much like the types in the signature. ([Location 7827](https://readwise.io/to_kindle?action=open&asin=B0B7QTX8LL&location=7827)) - When we pass concrete references to longest, the concrete lifetime that is substituted for 'a is the part of the scope of x that overlaps with the scope of y. In other words, the generic lifetime 'a will get the concrete lifetime that is equal to the smaller of the lifetimes of x and y. ([Location 7833](https://readwise.io/to_kindle?action=open&asin=B0B7QTX8LL&location=7833)) - If the reference returned does not refer to one of the parameters, it must refer to a value created within this function. However, this would be a dangling reference because the value will go out of scope at the end of the function. ([Location 7903](https://readwise.io/to_kindle?action=open&asin=B0B7QTX8LL&location=7903)) - So far, the structs we’ve defined all hold owned types. We can define structs to hold references, but in that case we would need to add a lifetime annotation on every reference in the struct’s definition. ([Location 7924](https://readwise.io/to_kindle?action=open&asin=B0B7QTX8LL&location=7924)) - The main function here creates an instance of the ImportantExcerpt struct ❺ that holds a reference to the first sentence of the String ❹ owned by the variable novel ❸. The data in novel exists before the ImportantExcerpt instance is created. In addition, novel doesn’t go out of scope until after the ImportantExcerpt goes out of scope, so the reference in the ImportantExcerpt instance is valid. ([Location 7942](https://readwise.io/to_kindle?action=open&asin=B0B7QTX8LL&location=7942)) - The patterns programmed into Rust’s analysis of references are called the lifetime elision rules. These aren’t rules for programmers to follow; they’re a set of particular cases that the compiler will consider, and if your code fits these cases, you don’t need to write the lifetimes explicitly. ([Location 7970](https://readwise.io/to_kindle?action=open&asin=B0B7QTX8LL&location=7970)) - Lifetimes on function or method parameters are called input lifetimes, and lifetimes on return values are called output lifetimes. ([Location 7975](https://readwise.io/to_kindle?action=open&asin=B0B7QTX8LL&location=7975)) - The compiler uses three rules to figure out the lifetimes of the references when there aren’t explicit annotations. The first rule applies to input lifetimes, and the second and third rules apply to output lifetimes. If the compiler gets to the end of the three rules and there are still references for which it can’t figure out lifetimes, the compiler will stop with an error. These rules apply to fn definitions as well as impl blocks. ([Location 7977](https://readwise.io/to_kindle?action=open&asin=B0B7QTX8LL&location=7977)) - The first rule is that the compiler assigns a lifetime parameter to each parameter that’s a reference. In other words, a function with one parameter gets one lifetime parameter: fn foo<'a>(x: &'a i32); a function with two parameters gets two separate lifetime parameters: fn foo<'a, 'b>(x: &'a i32, y: &'b i32); and so on. ([Location 7981](https://readwise.io/to_kindle?action=open&asin=B0B7QTX8LL&location=7981)) - The second rule is that, if there is exactly one input lifetime parameter, that lifetime is assigned to all output lifetime parameters: fn foo<'a>(x: &'a i32) -> &'a i32. ([Location 7985](https://readwise.io/to_kindle?action=open&asin=B0B7QTX8LL&location=7985)) - The third rule is that, if there are multiple input lifetime parameters, but one of them is &self or &mut self because this is a method, the lifetime of self is assigned to all output lifetime parameters. This third rule makes methods much nicer to read and write because fewer symbols are necessary. ([Location 7987](https://readwise.io/to_kindle?action=open&asin=B0B7QTX8LL&location=7987)) - fn first_word(s: &str) -> &str { Then the compiler applies the first rule, which specifies that each parameter gets its own lifetime. We’ll call it 'a as usual, so now the signature is this: ([Location 7994](https://readwise.io/to_kindle?action=open&asin=B0B7QTX8LL&location=7994)) - fn first_word<'a>(s: &'a str) -> &str { The second rule applies because there is exactly one input lifetime. The second rule specifies that the lifetime of the one input parameter gets assigned to the output lifetime, so the signature is now this: ([Location 7998](https://readwise.io/to_kindle?action=open&asin=B0B7QTX8LL&location=7998)) - fn first_word<'a>(s: &'a str) -> &'a str { Now all the references in this function signature have lifetimes, and the compiler can continue its analysis without needing the programmer to annotate the lifetimes in this function signature. ([Location 8002](https://readwise.io/to_kindle?action=open&asin=B0B7QTX8LL&location=8002)) - When we implement methods on a struct with lifetimes, we use the same syntax as that of generic type parameters, ([Location 8021](https://readwise.io/to_kindle?action=open&asin=B0B7QTX8LL&location=8021)) - Where we declare and use the lifetime parameters depends on whether they’re related to the struct fields or the method parameters and return values. Lifetime names for struct fields always need to be declared after the impl keyword and then used after the struct’s name because those lifetimes are part of the struct’s type. ([Location 8022](https://readwise.io/to_kindle?action=open&asin=B0B7QTX8LL&location=8022)) - One special lifetime we need to discuss is 'static, which denotes that the affected reference can live for the entire duration of the program. All string literals have the 'static lifetime, which we can annotate as follows: let s: &'static str = "I have a static lifetime."; ([Location 8046](https://readwise.io/to_kindle?action=open&asin=B0B7QTX8LL&location=8046)) - This is the longest function from Listing 10-21 that returns the longer of two string slices. But now it has an extra parameter named ann of the generic type T, which can be filled in by any type that implements the Display trait as specified by the where clause. This extra parameter will be printed using {}, which is why the Display trait bound is necessary. ([Location 8066](https://readwise.io/to_kindle?action=open&asin=B0B7QTX8LL&location=8066)) - Tests are Rust functions that verify that the non-test code is functioning in the expected manner. The bodies of test functions typically perform these three actions: Set up any needed data or state. Run the code you want to test. Assert that the results are what you expect. Let’s look at the features Rust provides specifically for writing tests that take these actions, which include the test attribute, a few macros, and the should_panic attribute. ([Location 8108](https://readwise.io/to_kindle?action=open&asin=B0B7QTX8LL&location=8108)) - At its simplest, a test in Rust is a function that’s annotated with the test attribute. Attributes are metadata about pieces of Rust code; one example is the derive attribute we used with structs in Chapter 5. To change a function into a test function, add #[test] on the line before fn. When you run your tests with the cargo test command, Rust builds a test runner binary that runs the annotated functions and reports on whether each test function passes or fails. ([Location 8115](https://readwise.io/to_kindle?action=open&asin=B0B7QTX8LL&location=8115)) - The assert! macro, provided by the standard library, is useful when you want to ensure that some condition in a test evaluates to true. We give the assert! macro an argument that evaluates to a Boolean. ([Location 8229](https://readwise.io/to_kindle?action=open&asin=B0B7QTX8LL&location=8229)) - Note that we’ve added a new line inside the tests module: use super::*; ❶. The tests module is a regular module that follows the usual visibility rules we covered in “Paths for Referring to an Item in the Module Tree” on page 125. Because the tests module is an inner module, we need to bring the code under test in the outer module into the scope of the inner module. We use a glob here, so anything we define in the outer module is available to this tests module. ([Location 8262](https://readwise.io/to_kindle?action=open&asin=B0B7QTX8LL&location=8262)) - However, this is such a common test that the standard library provides a pair of macros—assert_eq! and assert_ne!—to perform this test more conveniently. ([Location 8316](https://readwise.io/to_kindle?action=open&asin=B0B7QTX8LL&location=8316)) - The assert_ne! macro will pass if the two values we give it are not equal and fail if they’re equal. This macro is most useful for cases when we’re not sure what a value will be, but we know what the value definitely shouldn’t be. ([Location 8363](https://readwise.io/to_kindle?action=open&asin=B0B7QTX8LL&location=8363)) - traits. For structs and enums that you define yourself, you’ll need to implement PartialEq to assert equality of those types. You’ll also need to implement Debug to print the values when the assertion fails. ([Location 8373](https://readwise.io/to_kindle?action=open&asin=B0B7QTX8LL&location=8373)) - You can also add a custom message to be printed with the failure message as optional arguments to the assert!, assert_eq!, and assert_ne! macros. ([Location 8379](https://readwise.io/to_kindle?action=open&asin=B0B7QTX8LL&location=8379)) - Writing tests so they return a Result<T, E> enables you to use the question mark operator in the body of tests, which can be a convenient way to write tests that should fail if any operation within them returns an Err variant. ([Location 8532](https://readwise.io/to_kindle?action=open&asin=B0B7QTX8LL&location=8532)) - Just as cargo run compiles your code and then runs the resultant binary, cargo test compiles your code in test mode and runs the resultant test binary. ([Location 8543](https://readwise.io/to_kindle?action=open&asin=B0B7QTX8LL&location=8543)) - When you run multiple tests, by default they run in parallel using threads, meaning they finish running faster and you get feedback quicker. Because the tests are running at the same time, you must make sure your tests don’t depend on each other or on any shared state, including a shared environment, such as the current working directory or environment variables. ([Location 8554](https://readwise.io/to_kindle?action=open&asin=B0B7QTX8LL&location=8554)) - If you don’t want to run the tests in parallel or if you want more fine-grained control over the number of threads used, you can send the --test-threads flag and the number of threads you want to use to the test binary. ([Location 8563](https://readwise.io/to_kindle?action=open&asin=B0B7QTX8LL&location=8563)) - If we want to see printed values for passing tests as well, we can tell Rust to also show the output of successful tests with --show-output: ([Location 8596](https://readwise.io/to_kindle?action=open&asin=B0B7QTX8LL&location=8596)) - Sometimes, running a full test suite can take a long time. If you’re working on code in a particular area, you might want to run only the tests pertaining to that code. You can choose which tests to run by passing cargo test the name or names of the test(s) you want to run as an argument. ([Location 8610](https://readwise.io/to_kindle?action=open&asin=B0B7QTX8LL&location=8610)) - The Rust community thinks about tests in terms of two main categories: unit tests and integration tests. Unit tests are small and more focused, testing one module in isolation at a time, and can test private interfaces. Integration tests are entirely external to your library and use your code in the same way any other external code would, using only the public interface and potentially exercising multiple modules per test. ([Location 8681](https://readwise.io/to_kindle?action=open&asin=B0B7QTX8LL&location=8681)) - The purpose of unit tests is to test each unit of code in isolation from the rest of the code to quickly pinpoint where code is and isn’t working as expected. You’ll put unit tests in the src directory in each file with the code that they’re testing. ([Location 8687](https://readwise.io/to_kindle?action=open&asin=B0B7QTX8LL&location=8687)) - The #[cfg(test)] annotation on the tests module tells Rust to compile and run the test code only when you run cargo test, not when you run cargo build. This saves compile time when you only want to build the library and saves space in the resultant compiled artifact because the tests are not included. You’ll see that because integration tests go in a different directory, they don’t need the #[cfg(test)] annotation. However, because unit tests go in the same files as the code, you’ll use #[cfg(test)] to specify that they shouldn’t be included in the compiled result. ([Location 8692](https://readwise.io/to_kindle?action=open&asin=B0B7QTX8LL&location=8692)) - There’s debate within the testing community about whether or not private functions should be tested directly, and other languages make it difficult or impossible to test private functions. Regardless of which testing ideology you adhere to, Rust’s privacy rules do allow you to test private functions. ([Location 8712](https://readwise.io/to_kindle?action=open&asin=B0B7QTX8LL&location=8712)) - In Rust, integration tests are entirely external to your library. They use your library in the same way any other code would, which means they can only call functions that are part of your library’s public API. Their purpose is to test whether many parts of your library work together correctly. ([Location 8731](https://readwise.io/to_kindle?action=open&asin=B0B7QTX8LL&location=8731)) - The three sections of output include the unit tests, the integration test, and the doc tests. ([Location 8768](https://readwise.io/to_kindle?action=open&asin=B0B7QTX8LL&location=8768)) - As you add more integration tests, you might want to make more files in the tests directory to help organize them; for example, you can group the test functions by the functionality they’re testing. As mentioned earlier, each file in the tests directory is compiled as its own separate crate, which is useful for creating separate scopes to more closely imitate the way end users will be using your crate. ([Location 8789](https://readwise.io/to_kindle?action=open&asin=B0B7QTX8LL&location=8789)) - Having common appear in the test results with running 0 tests displayed for it is not what we wanted. We just wanted to share some code with the other integration test files. To avoid having common appear in the test output, instead of creating tests/common.rs, we’ll create tests/common/mod.rs. ([Location 8817](https://readwise.io/to_kindle?action=open&asin=B0B7QTX8LL&location=8817)) - If our project is a binary crate that only contains a src/main.rs file and doesn’t have a src/lib.rs file, we can’t create integration tests in the tests directory and bring functions defined in the src/main.rs file into scope with a use statement. Only library crates expose functions that other crates can use; binary crates are meant to be run on their own. ([Location 8843](https://readwise.io/to_kindle?action=open&asin=B0B7QTX8LL&location=8843)) - Rust’s speed, safety, single binary output, and cross-platform support make it an ideal language for creating command line tools, so for our project, we’ll make our own version of the classic command line search tool grep (globally search a regular expression and print). In the simplest use case, grep searches a specified file for a specified string. To do so, grep takes as its arguments a file path and a string. Then it reads the file, finds lines in that file that contain the string argument, and prints those lines. ([Location 8866](https://readwise.io/to_kindle?action=open&asin=B0B7QTX8LL&location=8866)) - We can use the collect function to create many kinds of collections, so we explicitly annotate the type of args to specify that we want a vector of strings. Although you very rarely need to annotate types in Rust, collect is one function you do often need to annotate because Rust isn’t able to infer the kind of collection you want. ([Location 8936](https://readwise.io/to_kindle?action=open&asin=B0B7QTX8LL&location=8936)) - Notice that the first value in the vector is "target/debug/minigrep", which is the name of our binary. This matches the behavior of the arguments list in C, letting programs use the name by which they were invoked in their execution. ([Location 8947](https://readwise.io/to_kindle?action=open&asin=B0B7QTX8LL&location=8947)) - Split your program into a main.rs file and a lib.rs file and move your program’s logic to lib.rs. As long as your command line parsing logic is small, it can remain in main.rs. When the command line parsing logic starts getting complicated, extract it from main.rs and move it to lib.rs. The responsibilities that remain in the main function after this process should be limited to the following: Calling the command line parsing logic with the argument values Setting up any other configuration Calling a run function in lib.rs Handling the error if run returns an error ([Location 9045](https://readwise.io/to_kindle?action=open&asin=B0B7QTX8LL&location=9045)) - call the clone method on the values ❼ ❽. This will make a full copy of the data for the Config instance to own, which takes more time and memory than storing a reference to the string data. However, cloning the data also makes our code very straightforward because we don’t have to manage the lifetimes of the references; in this circumstance, giving up a little performance to gain simplicity is a worthwhile trade-off. ([Location 9121](https://readwise.io/to_kindle?action=open&asin=B0B7QTX8LL&location=9121)) - It’s better to have a working program that’s a bit inefficient than to try to hyperoptimize code on your first pass. As you become more experienced with Rust, it’ll be easier to start with the most efficient solution, but for now, it’s perfectly acceptable to call clone. ([Location 9131](https://readwise.io/to_kindle?action=open&asin=B0B7QTX8LL&location=9131)) - So now that the purpose of the parse_config function is to create a Config instance, we can change parse_config from a plain function to a function named new that is associated with the Config struct. ([Location 9151](https://readwise.io/to_kindle?action=open&asin=B0B7QTX8LL&location=9151)) - We can instead return a Result value that will contain a Config instance in the successful case and will describe the problem in the error case. We’re also going to change the function name from new to build because many programmers expect new functions to never fail. ([Location 9217](https://readwise.io/to_kindle?action=open&asin=B0B7QTX8LL&location=9217)) - Our error values will always be string literals that have the 'static lifetime. ([Location 9242](https://readwise.io/to_kindle?action=open&asin=B0B7QTX8LL&location=9242)) - A nonzero exit status is a convention to signal to the process that called our program that the program exited with an error state. ([Location 9256](https://readwise.io/to_kindle?action=open&asin=B0B7QTX8LL&location=9256)) - unwrap_or_else, which is defined on Result<T, E> by the standard library ❷. Using unwrap_or_else allows us to define some custom, non-panic! error handling. ([Location 9268](https://readwise.io/to_kindle?action=open&asin=B0B7QTX8LL&location=9268)) - closure, which is an anonymous function we define and pass as an argument to unwrap_or_else ([Location 9273](https://readwise.io/to_kindle?action=open&asin=B0B7QTX8LL&location=9273)) - used the trait object Box<dyn Error> (and we’ve brought std::error::Error into scope with a use statement at the top ❶). We’ll cover trait objects in Chapter 17. For now, just know that Box<dyn Error> means the function will return a type that implements the Error trait, but we don’t have to specify what particular type the return value will be. ([Location 9336](https://readwise.io/to_kindle?action=open&asin=B0B7QTX8LL&location=9336)) - The dyn keyword is short for dynamic. ([Location 9341](https://readwise.io/to_kindle?action=open&asin=B0B7QTX8LL&location=9341)) - Rather than panic! on an error, ? will return the error value from the current function for the caller to handle. ([Location 9345](https://readwise.io/to_kindle?action=open&asin=B0B7QTX8LL&location=9345)) - This Ok(()) syntax might look a bit strange at first, but using () like this is the idiomatic way to indicate that we’re calling run for its side effects only; it doesn’t return a value we need. ([Location 9350](https://readwise.io/to_kindle?action=open&asin=B0B7QTX8LL&location=9350)) - We use if let rather than unwrap_or_else to check whether run returns an Err value and to call process::exit(1) if it does. The run function doesn’t return a value that we want to unwrap in the same way that Config::build returns the Config instance. Because run returns () in the success case, we only care about detecting an error, so we don’t need unwrap_or_else to return the unwrapped value, which would only be (). ([Location 9371](https://readwise.io/to_kindle?action=open&asin=B0B7QTX8LL&location=9371)) - test-driven development (TDD) process with the following steps: Write a test that fails and run it to make sure it fails for the reason you expect. Write or modify just enough code to make the new test pass. Refactor the code you just added or changed and make sure the tests continue to pass. Repeat from step 1! ([Location 9433](https://readwise.io/to_kindle?action=open&asin=B0B7QTX8LL&location=9433)) - In other words, we tell Rust that the data returned by the search function will live as long as the data passed into the search function in the contents argument. This is important! The data referenced by a slice needs to be valid for the reference to be valid; if the compiler assumes we’re making string slices of query rather than contents, it will do its safety checking incorrectly. ([Location 9479](https://readwise.io/to_kindle?action=open&asin=B0B7QTX8LL&location=9479)) - If the IGNORE_CASE environment variable isn’t set to anything, is_ok will return false and the program will perform a case-sensitive search. ([Location 9733](https://readwise.io/to_kindle?action=open&asin=B0B7QTX8LL&location=9733)) - The standard library provides the eprintln! macro that prints to the standard error stream, so let’s change the two places we were calling println! to print errors to use eprintln! instead. ([Location 9803](https://readwise.io/to_kindle?action=open&asin=B0B7QTX8LL&location=9803)) - Programming in a functional style often includes using functions as values by passing them in arguments, returning them from other functions, assigning them to variables for later execution, and so forth. ([Location 9842](https://readwise.io/to_kindle?action=open&asin=B0B7QTX8LL&location=9842)) - Closures, a function-like construct you can store in a variable ([Location 9847](https://readwise.io/to_kindle?action=open&asin=B0B7QTX8LL&location=9847)) - Iterators, a way of processing a series of elements ([Location 9848](https://readwise.io/to_kindle?action=open&asin=B0B7QTX8LL&location=9848)) - Rust’s closures are anonymous functions you can save in a variable or pass as arguments to other functions. You can create the closure in one place and then call the closure elsewhere to evaluate it in a different context. ([Location 9855](https://readwise.io/to_kindle?action=open&asin=B0B7QTX8LL&location=9855)) - We specify the closure expression || self.most_stocked() as the argument to unwrap_or_else. This is a closure that takes no parameters itself (if the closure had parameters, they would appear between the two vertical pipes). The body of the closure calls self.most_stocked(). We’re defining the closure here, and the implementation of unwrap_or_else will evaluate the closure later if the result is needed. ([Location 9911](https://readwise.io/to_kindle?action=open&asin=B0B7QTX8LL&location=9911)) - There are more differences between functions and closures. Closures don’t usually require you to annotate the types of the parameters or the return value like fn functions do. Type annotations are required on functions because the types are part of an explicit interface exposed to your users. Defining this interface rigidly is important for ensuring that everyone agrees on what types of values a function uses and returns. Closures, on the other hand, aren’t used in an exposed interface like this: they’re stored in variables and used without naming them and exposing them to users of our library. ([Location 9925](https://readwise.io/to_kindle?action=open&asin=B0B7QTX8LL&location=9925)) - Closures are typically short and relevant only within a narrow context rather than in any arbitrary scenario. ([Location 9930](https://readwise.io/to_kindle?action=open&asin=B0B7QTX8LL&location=9930)) - The first time we call example_closure with the String value, the compiler infers the type of x and the return type of the closure to be String. Those types are then locked into the closure in example_closure, and we get a type error when we next try to use a different type with the same closure. ([Location 9973](https://readwise.io/to_kindle?action=open&asin=B0B7QTX8LL&location=9973)) - Closures can capture values from their environment in three ways, which directly map to the three ways a function can take a parameter: borrowing immutably, borrowing mutably, and taking ownership. The closure will decide which of these to use based on what the body of the function does with the captured values. ([Location 9979](https://readwise.io/to_kindle?action=open&asin=B0B7QTX8LL&location=9979)) - If you want to force the closure to take ownership of the values it uses in the environment even though the body of the closure doesn’t strictly need ownership, you can use the move keyword before the parameter list. ([Location 10018](https://readwise.io/to_kindle?action=open&asin=B0B7QTX8LL&location=10018)) - The new thread might finish before the rest of the main thread finishes, or the main thread might finish first. If the main thread maintains ownership of list but ends before the new thread and drops list, the immutable reference in the thread would be invalid. Therefore, the compiler requires that list be moved into the closure given to the new thread so the reference will be valid. ([Location 10040](https://readwise.io/to_kindle?action=open&asin=B0B7QTX8LL&location=10040)) - Once a closure has captured a reference or captured ownership of a value from the environment where the closure is defined (thus affecting what, if anything, is moved into the closure), the code in the body of the closure defines what happens to the references or values when the closure is evaluated later (thus affecting what, if anything, is moved out of the closure). ([Location 10047](https://readwise.io/to_kindle?action=open&asin=B0B7QTX8LL&location=10047)) - A closure body can do any of the following: move a captured value out of the closure, mutate the captured value, neither move nor mutate the value, or capture nothing from the environment to begin with. ([Location 10050](https://readwise.io/to_kindle?action=open&asin=B0B7QTX8LL&location=10050)) - FnOnce applies to closures that can be called once. All closures implement at least this trait because all closures can be called. A closure that moves captured values out of its body will only implement FnOnce and none of the other Fn traits because it can only be called once. ([Location 10056](https://readwise.io/to_kindle?action=open&asin=B0B7QTX8LL&location=10056)) - FnMut applies to closures that don’t move captured values out of their body, but that might mutate the captured values. These closures can be called more than once. ([Location 10059](https://readwise.io/to_kindle?action=open&asin=B0B7QTX8LL&location=10059)) - Fn applies to closures that don’t move captured values out of their body and that don’t mutate captured values, as well as closures that capture nothing from their environment. These closures can be called more than once without mutating their environment, which is important in cases such as calling a closure multiple times concurrently. ([Location 10061](https://readwise.io/to_kindle?action=open&asin=B0B7QTX8LL&location=10061)) - Functions can implement all three of the Fn traits too. ([Location 10091](https://readwise.io/to_kindle?action=open&asin=B0B7QTX8LL&location=10091)) - The reason sort_by_key is defined to take an FnMut closure is that it calls the closure multiple times: once for each item in the slice. The closure |r| r.width doesn’t capture, mutate, or move anything out from its environment, so it meets the trait bound requirements. ([Location 10118](https://readwise.io/to_kindle?action=open&asin=B0B7QTX8LL&location=10118)) - The error points to the line in the closure body that moves value out of the environment. To fix this, we need to change the closure body so that it doesn’t move values out of the environment. Keeping a counter in the environment and incrementing its value in the closure body is a more straightforward way to count the number of times sort_by_key is called. ([Location 10154](https://readwise.io/to_kindle?action=open&asin=B0B7QTX8LL&location=10154)) - Iterators handle all of that logic for you, cutting down on repetitive code you could potentially mess up. ([Location 10198](https://readwise.io/to_kindle?action=open&asin=B0B7QTX8LL&location=10198)) - Notice that this definition uses some new syntax: type Item and Self::Item, which are defining an associated type with this trait. ([Location 10207](https://readwise.io/to_kindle?action=open&asin=B0B7QTX8LL&location=10207)) - The Iterator trait only requires implementors to define one method: the next method, which returns one item of the iterator at a time, wrapped in Some, and, when iteration is over, returns None. ([Location 10213](https://readwise.io/to_kindle?action=open&asin=B0B7QTX8LL&location=10213)) - Also note that the values we get from the calls to next are immutable references to the values in the vector. The iter method produces an iterator over immutable references. If we want to create an iterator that takes ownership of v1 and returns owned values, we can call into_iter instead of iter. Similarly, if we want to iterate over mutable references, we can call iter_mut instead of iter. ([Location 10232](https://readwise.io/to_kindle?action=open&asin=B0B7QTX8LL&location=10232)) - Iterator adapters are methods defined on the Iterator trait that don’t consume the iterator. Instead, they produce different iterators by changing some aspect of the original iterator. ([Location 10260](https://readwise.io/to_kindle?action=open&asin=B0B7QTX8LL&location=10260)) - The code in Listing 13-14 doesn’t do anything; the closure we’ve specified never gets called. The warning reminds us why: iterator adapters are lazy, and we need to consume the iterator here. ([Location 10275](https://readwise.io/to_kindle?action=open&asin=B0B7QTX8LL&location=10275)) - Because map takes a closure, we can specify any operation we want to perform on each item. This is a great example of how closures let you customize some behavior while reusing the iteration behavior that the Iterator trait provides. ([Location 10289](https://readwise.io/to_kindle?action=open&asin=B0B7QTX8LL&location=10289)) - Many iterator adapters take closures as arguments, and commonly the closures we’ll specify as arguments to iterator adapters will be closures that capture their environment. ([Location 10295](https://readwise.io/to_kindle?action=open&asin=B0B7QTX8LL&location=10295)) - The env::args function returns an iterator! Rather than collecting the iterator values into a vector and then passing a slice to Config::build, now we’re passing ownership of the iterator returned from env::args to Config::build directly. ([Location 10393](https://readwise.io/to_kindle?action=open&asin=B0B7QTX8LL&location=10393)) - We’ve updated the signature of the Config::build function so the parameter args has a generic type with the trait bounds impl Iterator<Item = String> instead of &[String]. This usage of the impl Trait syntax we discussed in “Traits as Parameters” on page 197 means that args can be any type that implements the Iterator type and returns String items. ([Location 10411](https://readwise.io/to_kindle?action=open&asin=B0B7QTX8LL&location=10411)) - Most Rust programmers prefer to use the iterator style. It’s a bit tougher to get the hang of at first, but once you get a feel for the various iterator adapters and what they do, iterators can be easier to understand. Instead of fiddling with the various bits of looping and building new vectors, the code focuses on the high-level objective of the loop. This abstracts away some of the commonplace code so it’s easier to see the concepts that are unique to this code, such as the filtering condition each element in the iterator must pass. ([Location 10484](https://readwise.io/to_kindle?action=open&asin=B0B7QTX8LL&location=10484)) - Unrolling is an optimization that removes the overhead of the loop controlling code and instead generates repetitive code for each iteration of the loop. ([Location 10532](https://readwise.io/to_kindle?action=open&asin=B0B7QTX8LL&location=10532)) - All of the coefficients get stored in registers, which means accessing the values is very fast. There are no bounds checks on the array access at runtime. ([Location 10534](https://readwise.io/to_kindle?action=open&asin=B0B7QTX8LL&location=10534)) - release profiles are predefined and customizable profiles with different configurations that allow a programmer to have more control over various options for compiling code. ([Location 10557](https://readwise.io/to_kindle?action=open&asin=B0B7QTX8LL&location=10557)) - Cargo has two main profiles: the dev profile Cargo uses when you run cargo build, and the release profile Cargo uses when you run cargo build --release. The dev profile is defined with good defaults for development, and the release profile has good defaults for release builds. ([Location 10559](https://readwise.io/to_kindle?action=open&asin=B0B7QTX8LL&location=10559)) - By adding [profile.*] sections for any profile you want to customize, you override any subset of the default settings. For example, here are the default values for the opt-level setting for the dev and release profiles: ([Location 10571](https://readwise.io/to_kindle?action=open&asin=B0B7QTX8LL&location=10571)) - The opt-level setting controls the number of optimizations Rust will apply to your code, with a range of 0 to 3. Applying more optimizations extends compiling time, so if you’re in development and compiling your code often, you’ll want fewer optimizations to compile faster even if the resultant code runs slower. The default opt-level for dev is therefore 0. ([Location 10577](https://readwise.io/to_kindle?action=open&asin=B0B7QTX8LL&location=10577)) - Rust also has a particular kind of comment for documentation, known conveniently as a documentation comment, that will generate HTML documentation. The HTML displays the contents of documentation comments for public API items intended for programmers interested in knowing how to use your crate as opposed to how your crate is implemented. Documentation comments use three slashes, ///, instead of two and support Markdown notation for formatting the text. ([Location 10606](https://readwise.io/to_kindle?action=open&asin=B0B7QTX8LL&location=10606)) - We used the # Examples Markdown heading in Listing 14-1 to create a section in the HTML with the title “Examples.” Here are some other sections that crate authors commonly use in their documentation: Panics The scenarios in which the function being documented could panic. Callers of the function who don’t want their programs to panic should make sure they don’t call the function in these situations. Errors If the function returns a Result, describing the kinds of errors that might occur and what conditions might cause those errors to be returned can be helpful to callers so they can write code to handle the different kinds of errors in different ways. Safety If the function is unsafe to call (we discuss unsafety in Chapter 19), there should be a section explaining why the function is unsafe and covering the invariants that the function expects callers to uphold. ([Location 10634](https://readwise.io/to_kindle?action=open&asin=B0B7QTX8LL&location=10634)) - The doc comment //! adds documentation to the item that contains the comments rather than to the items following the comments. We typically use these doc comments inside the crate root file (src/lib.rs by convention) or inside a module to document the crate or the module as a whole. ([Location 10660](https://readwise.io/to_kindle?action=open&asin=B0B7QTX8LL&location=10660)) - Notice there isn’t any code after the last line that begins with //!. Because we started the comments with //! instead of ///, we’re documenting the item that contains this comment rather than an item that follows this comment. ([Location 10674](https://readwise.io/to_kindle?action=open&asin=B0B7QTX8LL&location=10674)) - The good news is that if the structure isn’t convenient for others to use from another library, you don’t have to rearrange your internal organization: instead, you can re-export items to make a public structure that’s different from your private structure by using pub use. Re-exporting takes a public item in one location and makes it public in another location, as if it were defined in the other location instead. ([Location 10700](https://readwise.io/to_kindle?action=open&asin=B0B7QTX8LL&location=10700)) - In cases where there are many nested modules, re-exporting the types at the top level with pub use can make a significant difference in the experience of people who use the crate. Another common use of pub use is to re-export definitions of a dependency in the current crate to make that crate’s definitions part of your crate’s public API. ([Location 10782](https://readwise.io/to_kindle?action=open&asin=B0B7QTX8LL&location=10782)) - Your crate will need a unique name. While you’re working on a crate locally, you can name a crate whatever you’d like. However, crate names on https://crates.io are allocated on a first-come, first-served basis. Once a crate name is taken, no one else can publish a crate with that name. ([Location 10805](https://readwise.io/to_kindle?action=open&asin=B0B7QTX8LL&location=10805)) - Yanking a version prevents new projects from depending on that version while allowing all existing projects that depend on it to continue. Essentially, a yank means that all projects with a Cargo.lock will not break, and any future Cargo.lock files generated will not use the yanked version. ([Location 10870](https://readwise.io/to_kindle?action=open&asin=B0B7QTX8LL&location=10870)) - A workspace is a set of packages that share the same Cargo.lock and output directory. ([Location 10892](https://readwise.io/to_kindle?action=open&asin=B0B7QTX8LL&location=10892)) - We can also run tests for one particular crate in a workspace from the top-level directory by using the -p flag and specifying the name of the crate we want to test: ([Location 11039](https://readwise.io/to_kindle?action=open&asin=B0B7QTX8LL&location=11039)) - The cargo install command allows you to install and use binary crates locally. This isn’t intended to replace system packages; it’s meant to be a convenient way for Rust developers to install tools that others have shared on https://crates.io. ([Location 11058](https://readwise.io/to_kindle?action=open&asin=B0B7QTX8LL&location=11058)) - Note that you can only install packages that have binary targets. A binary target is the runnable program that is created if the crate has a src/main.rs file or another file specified as a binary, as opposed to a library target that isn’t runnable on its own but is suitable for including within other programs. ([Location 11060](https://readwise.io/to_kindle?action=open&asin=B0B7QTX8LL&location=11060)) - A pointer is a general concept for a variable that contains an address in memory. This address refers to, or “points at,” some other data. The most common kind of pointer in Rust is a reference, ([Location 11097](https://readwise.io/to_kindle?action=open&asin=B0B7QTX8LL&location=11097)) - References are indicated by the & symbol and borrow the value they point to. They don’t have any special capabilities other than referring to data, and they have no overhead. ([Location 11099](https://readwise.io/to_kindle?action=open&asin=B0B7QTX8LL&location=11099)) - Smart pointers, on the other hand, are data structures that act like a pointer but also have additional metadata and capabilities. ([Location 11101](https://readwise.io/to_kindle?action=open&asin=B0B7QTX8LL&location=11101)) - reference counting smart pointer type. This pointer enables you to allow data to have multiple owners by keeping track of the number of owners and, when no owners remain, cleaning up the data. ([Location 11105](https://readwise.io/to_kindle?action=open&asin=B0B7QTX8LL&location=11105)) - while references only borrow data, in many cases smart pointers own the data they point to. ([Location 11108](https://readwise.io/to_kindle?action=open&asin=B0B7QTX8LL&location=11108)) - Smart pointers are usually implemented using structs. Unlike an ordinary struct, smart pointers implement the Deref and Drop traits. The Deref trait allows an instance of the smart pointer struct to behave like a reference so you can write your code to work with either references or smart pointers. The Drop trait allows you to customize the code that’s run when an instance of the smart pointer goes out of scope. ([Location 11114](https://readwise.io/to_kindle?action=open&asin=B0B7QTX8LL&location=11114)) - Box<T>, for allocating values on the heap ([Location 11122](https://readwise.io/to_kindle?action=open&asin=B0B7QTX8LL&location=11122)) - Rc<T>, a reference counting type that enables multiple ownership ([Location 11123](https://readwise.io/to_kindle?action=open&asin=B0B7QTX8LL&location=11123)) - Ref<T> and RefMut<T>, accessed through RefCell<T>, a type that enforces the borrowing rules at runtime instead of compile time ([Location 11124](https://readwise.io/to_kindle?action=open&asin=B0B7QTX8LL&location=11124)) - interior mutability pattern where an immutable type exposes an API for mutating an interior value. ([Location 11127](https://readwise.io/to_kindle?action=open&asin=B0B7QTX8LL&location=11127)) - The most straightforward smart pointer is a box, whose type is written Box<T>. Boxes allow you to store data on the heap rather than the stack. What remains on the stack is the pointer to the heap data. ([Location 11131](https://readwise.io/to_kindle?action=open&asin=B0B7QTX8LL&location=11131)) - Boxes don’t have performance overhead, other than storing their data on the heap instead of on the stack. But they don’t have many extra capabilities either. You’ll use them most often in these situations: When you have a type whose size can’t be known at compile time and you want to use a value of that type in a context that requires an exact size When you have a large amount of data and you want to transfer ownership but ensure the data won’t be copied when you do so When you want to own a value and you care only that it’s a type that implements a particular trait rather than being of a specific type ([Location 11134](https://readwise.io/to_kindle?action=open&asin=B0B7QTX8LL&location=11134)) - transferring ownership of a large amount of data can take a long time because the data is copied around on the stack. To improve performance in this situation, we can store the large amount of data on the heap in a box. Then, only the small amount of pointer data is copied around on the stack, while the data it references stays in one place on the heap. ([Location 11142](https://readwise.io/to_kindle?action=open&asin=B0B7QTX8LL&location=11142)) - a trait object, and “Using Trait Objects That Allow for Values of Different Types” on page 379 is devoted to that topic. So what you learn here you’ll apply again in that section! ([Location 11144](https://readwise.io/to_kindle?action=open&asin=B0B7QTX8LL&location=11144)) - A value of a recursive type can have another value of the same type as part of itself. Recursive types pose an issue because, at compile time, Rust needs to know how much space a type takes up. However, the nesting of values of recursive types could theoretically continue infinitely, so Rust can’t know how much space the value needs. Because boxes have a known size, we can enable recursive types by inserting a box in the recursive type definition. ([Location 11168](https://readwise.io/to_kindle?action=open&asin=B0B7QTX8LL&location=11168)) - A cons list is a data structure that comes from the Lisp programming language and its dialects, is made up of nested pairs, and is the Lisp version of a linked list. Its name comes from the cons function (short for construct function) in Lisp that constructs a new pair from its two arguments. ([Location 11177](https://readwise.io/to_kindle?action=open&asin=B0B7QTX8LL&location=11177)) - The error shows this type “has infinite size.” The reason is that we’ve defined List with a variant that is recursive: it holds another value of itself directly. As a result, Rust can’t figure out how much space it needs to store a List value. ([Location 11230](https://readwise.io/to_kindle?action=open&asin=B0B7QTX8LL&location=11230)) - The compiler starts by looking at the Cons variant, which holds a value of type i32 and a value of type List. Therefore, Cons needs an amount of space equal to the size of an i32 plus the size of a List. To figure out how much memory the List type needs, the compiler looks at the variants, starting with the Cons variant. The Cons variant holds a value of type i32 and a value of type List, and this process continues infinitely, ([Location 11246](https://readwise.io/to_kindle?action=open&asin=B0B7QTX8LL&location=11246)) - indirection means that instead of storing a value directly, we should change the data structure to store the value indirectly by storing a pointer to the value instead. ([Location 11266](https://readwise.io/to_kindle?action=open&asin=B0B7QTX8LL&location=11266)) - Because a Box<T> is a pointer, Rust always knows how much space a Box<T> needs: a pointer’s size doesn’t change based on the amount of data it’s pointing to. This means we can put a Box<T> inside the Cons variant instead of another List value directly. The Box<T> will point to the next List value that will be on the heap rather than inside the Cons variant. ([Location 11268](https://readwise.io/to_kindle?action=open&asin=B0B7QTX8LL&location=11268)) - Boxes provide only the indirection and heap allocation; they don’t have any other special capabilities, ([Location 11302](https://readwise.io/to_kindle?action=open&asin=B0B7QTX8LL&location=11302)) - The Box<T> type is a smart pointer because it implements the Deref trait, which allows Box<T> values to be treated like references. When a Box<T> value goes out of scope, the heap data that the box is pointing to is cleaned up as well because of the Drop trait implementation. ([Location 11305](https://readwise.io/to_kindle?action=open&asin=B0B7QTX8LL&location=11305)) - Implementing the Deref trait allows you to customize the behavior of the dereference operator * (not to be confused with the multiplication or glob operator). By implementing Deref in such a way that a smart pointer can be treated like a regular reference, you can write code that operates on references and use that code with smart pointers too. ([Location 11312](https://readwise.io/to_kindle?action=open&asin=B0B7QTX8LL&location=11312)) - There’s one big difference between the MyBox<T> type we’re about to build and the real Box<T>: our version will not store its data on the heap. We are focusing this example on Deref, so where the data is actually stored is less important than the pointer-like behavior. ([Location 11324](https://readwise.io/to_kindle?action=open&asin=B0B7QTX8LL&location=11324)) - we have to use *y to follow the reference to the value it’s pointing to (hence dereference) so the compiler can compare the actual value ([Location 11343](https://readwise.io/to_kindle?action=open&asin=B0B7QTX8LL&location=11343)) - We can rewrite the code in Listing 15-6 to use a Box<T> instead of a reference; the dereference operator used on the Box<T> in Listing 15-7 functions in the same way as the dereference operator used on the reference ([Location 11356](https://readwise.io/to_kindle?action=open&asin=B0B7QTX8LL&location=11356)) - The main difference between Listing 15-7 and Listing 15-6 is that here we set y to be an instance of a box pointing to a copied value of x rather than a reference pointing to the value of x ❶. In the last assertion ❷, we can use the dereference operator to follow the box’s pointer in the same way that we did when y was a reference. ([Location 11368](https://readwise.io/to_kindle?action=open&asin=B0B7QTX8LL&location=11368)) - The Box<T> type is ultimately defined as a tuple struct with one element, ([Location 11378](https://readwise.io/to_kindle?action=open&asin=B0B7QTX8LL&location=11378)) - Our MyBox<T> type can’t be dereferenced because we haven’t implemented that ability on our type. To enable dereferencing with the * operator, we implement the Deref trait. ([Location 11411](https://readwise.io/to_kindle?action=open&asin=B0B7QTX8LL&location=11411)) - The Deref trait, provided by the standard library, requires us to implement one method named deref that borrows self and returns a reference to the inner data. ([Location 11417](https://readwise.io/to_kindle?action=open&asin=B0B7QTX8LL&location=11417)) - The type Target = T; syntax ❶ defines an associated type for the Deref trait to use. ([Location 11428](https://readwise.io/to_kindle?action=open&asin=B0B7QTX8LL&location=11428)) - We fill in the body of the deref method with &self.0 so deref returns a reference to the value we want to access with the * operator ([Location 11432](https://readwise.io/to_kindle?action=open&asin=B0B7QTX8LL&location=11432)) - .0 accesses the first value in a tuple struct. ([Location 11437](https://readwise.io/to_kindle?action=open&asin=B0B7QTX8LL&location=11437)) - Rust substitutes the * operator with a call to the deref method and then a plain dereference so we don’t have to think about whether or not we need to call the deref method. ([Location 11447](https://readwise.io/to_kindle?action=open&asin=B0B7QTX8LL&location=11447)) - The reason the deref method returns a reference to a value, and that the plain dereference outside the parentheses in *(y.deref()) is still necessary, has to do with the ownership system. ([Location 11451](https://readwise.io/to_kindle?action=open&asin=B0B7QTX8LL&location=11451)) - Deref coercion converts a reference to a type that implements the Deref trait into a reference to another type. For example, deref coercion can convert &String to &str because String implements the Deref trait such that it returns &str. ([Location 11464](https://readwise.io/to_kindle?action=open&asin=B0B7QTX8LL&location=11464)) - Deref coercion was added to Rust so that programmers writing function and method calls don’t need to add as many explicit references and dereferences with & and *. The deref coercion feature also lets us write more code that can work for either references or smart pointers. ([Location 11472](https://readwise.io/to_kindle?action=open&asin=B0B7QTX8LL&location=11472)) - We can call the hello function with a string slice as an argument, such as hello("Rust");, for example. Deref coercion makes it possible to call hello with a reference to a value of type MyBox<String>, ([Location 11485](https://readwise.io/to_kindle?action=open&asin=B0B7QTX8LL&location=11485)) - The (*m) dereferences the MyBox<String> into a String. Then the & and [..] take a string slice of the String that is equal to the whole string to match the signature of hello. ([Location 11513](https://readwise.io/to_kindle?action=open&asin=B0B7QTX8LL&location=11513)) - Similar to how you use the Deref trait to override the * operator on immutable references, you can use the DerefMut trait to override the * operator on mutable references. ([Location 11524](https://readwise.io/to_kindle?action=open&asin=B0B7QTX8LL&location=11524)) - Rust does deref coercion when it finds types and trait implementations in three cases: From &T to &U when T: Deref<Target=U> From &mut T to &mut U when T: DerefMut<Target=U> From &mut T to &U when T: Deref<Target=U> ([Location 11527](https://readwise.io/to_kindle?action=open&asin=B0B7QTX8LL&location=11527)) - The third case is trickier: Rust will also coerce a mutable reference to an immutable one. But the reverse is not possible: immutable references will never coerce to mutable references. Because of the borrowing rules, if you have a mutable reference, that mutable reference must be the only reference to that data (otherwise, the program wouldn’t compile). ([Location 11538](https://readwise.io/to_kindle?action=open&asin=B0B7QTX8LL&location=11538)) - The second trait important to the smart pointer pattern is Drop, which lets you customize what happens when a value is about to go out of scope. You can provide an implementation for the Drop trait on any type, and that code can be used to release resources like files or network connections. ([Location 11545](https://readwise.io/to_kindle?action=open&asin=B0B7QTX8LL&location=11545)) - We’re introducing Drop in the context of smart pointers because the functionality of the Drop trait is almost always used when implementing a smart pointer. For example, when a Box<T> is dropped, it will deallocate the space on the heap that the box points to. ([Location 11548](https://readwise.io/to_kindle?action=open&asin=B0B7QTX8LL&location=11548)) - The Drop trait is included in the prelude, so we don’t need to bring it into scope. We implement the Drop trait on CustomSmartPointer ❶ and provide an implementation for the drop method that calls println! ([Location 11577](https://readwise.io/to_kindle?action=open&asin=B0B7QTX8LL&location=11577)) - Disabling drop isn’t usually necessary; the whole point of the Drop trait is that it’s taken care of automatically. Occasionally, however, you might want to clean up a value early. One example is when using smart pointers that manage locks: you might want to force the drop method that releases the lock so that other code in the same scope can acquire the lock. ([Location 11599](https://readwise.io/to_kindle?action=open&asin=B0B7QTX8LL&location=11599)) - This error message states that we’re not allowed to explicitly call drop. The error message uses the term destructor, which is the general programming term for a function that cleans up an instance. A destructor is analogous to a constructor, which creates an instance. The drop function in Rust is one particular destructor. ([Location 11624](https://readwise.io/to_kindle?action=open&asin=B0B7QTX8LL&location=11624)) - Rust doesn’t let us call drop explicitly because Rust would still automatically call drop on the value at the end of main. This would cause a double free error because Rust would be trying to clean up the same value twice. ([Location 11628](https://readwise.io/to_kindle?action=open&asin=B0B7QTX8LL&location=11628)) - However, there are cases when a single value might have multiple owners. For example, in graph data structures, multiple edges might point to the same node, and that node is conceptually owned by all of the edges that point to it. A node shouldn’t be cleaned up unless it doesn’t have any edges pointing to it and so has no owners. ([Location 11666](https://readwise.io/to_kindle?action=open&asin=B0B7QTX8LL&location=11666)) - You have to enable multiple ownership explicitly by using the Rust type Rc<T>, which is an abbreviation for reference counting. The Rc<T> type keeps track of the number of references to a value to determine whether or not the value is still in use. If there are zero references to a value, the value can be cleaned up without any references becoming invalid. ([Location 11668](https://readwise.io/to_kindle?action=open&asin=B0B7QTX8LL&location=11668)) - Imagine Rc<T> as a TV in a family room. When one person enters to watch TV, they turn it on. Others can come into the room and watch the TV. When the last person leaves the room, they turn off the TV because it’s no longer being used. If someone turns off the TV while others are still watching it, there would be an uproar from the remaining TV watchers! ([Location 11673](https://readwise.io/to_kindle?action=open&asin=B0B7QTX8LL&location=11673)) - Note that Rc<T> is only for use in single-threaded scenarios. ([Location 11679](https://readwise.io/to_kindle?action=open&asin=B0B7QTX8LL&location=11679)) - When we create b, instead of taking ownership of a, we’ll clone the Rc<List> that a is holding, thereby increasing the number of references from one to two and letting a and b share ownership of the data in that Rc<List>. We’ll also clone a when creating c, increasing the number of references from two to three. Every time we call Rc::clone, the reference count to the data within the Rc<List> will increase, and the data won’t be cleaned up unless there are zero references to it. ([Location 11731](https://readwise.io/to_kindle?action=open&asin=B0B7QTX8LL&location=11731)) - We need to add a use statement to bring Rc<T> into scope ❶ because it’s not in the prelude. In main, we create the list holding 5 and 10 and store it in a new Rc<List> in a ❷. Then, when we create b ❸ and c ❹, we call the Rc::clone function and pass a reference to the Rc<List> in a as an argument. ([Location 11749](https://readwise.io/to_kindle?action=open&asin=B0B7QTX8LL&location=11749)) - case. The implementation of Rc::clone doesn’t make a deep copy of all the data like most types’ implementations of clone do. The call to Rc::clone only increments the reference count, which doesn’t take much time. Deep copies of data can take a lot of time. By using Rc::clone for reference counting, we can visually distinguish between the deep-copy kinds of clones and the kinds of clones that increase the reference count. When looking for performance problems in the code, we only need to consider the deep-copy clones and can disregard calls to Rc::clone. ([Location 11759](https://readwise.io/to_kindle?action=open&asin=B0B7QTX8LL&location=11759)) - At each point in the program where the reference count changes, we print the reference count, which we get by calling the Rc::strong_count function. This function is named strong_count rather than count because the Rc<T> type also has a weak_count; ([Location 11785](https://readwise.io/to_kindle?action=open&asin=B0B7QTX8LL&location=11785)) - We can see that the Rc<List> in a has an initial reference count of 1; then each time we call clone, the count goes up by 1. ([Location 11794](https://readwise.io/to_kindle?action=open&asin=B0B7QTX8LL&location=11794)) - If Rc<T> allowed you to have multiple mutable references too, you might violate one of the borrowing rules ([Location 11806](https://readwise.io/to_kindle?action=open&asin=B0B7QTX8LL&location=11806)) - Interior mutability is a design pattern in Rust that allows you to mutate data even when there are immutable references to that data; normally, this action is disallowed by the borrowing rules. To mutate data, the pattern uses unsafe code inside a data structure to bend Rust’s usual rules that govern mutation and borrowing. Unsafe code indicates to the compiler that we’re checking the rules manually instead of relying on the compiler to check them for us; ([Location 11812](https://readwise.io/to_kindle?action=open&asin=B0B7QTX8LL&location=11812)) - Unlike Rc<T>, the RefCell<T> type represents single ownership over the data it holds. ([Location 11822](https://readwise.io/to_kindle?action=open&asin=B0B7QTX8LL&location=11822)) - what makes RefCell<T> different from a type like Box<T>? Recall the borrowing rules you learned in Chapter 4: At any given time, you can have either one mutable reference or any number of immutable references (but not both). References must always be valid. ([Location 11824](https://readwise.io/to_kindle?action=open&asin=B0B7QTX8LL&location=11824)) - With references and Box<T>, the borrowing rules’ invariants are enforced at compile time. With RefCell<T>, these invariants are enforced at runtime. With references, if you break these rules, you’ll get a compiler error. With RefCell<T>, if you break these rules, your program will panic and exit. ([Location 11828](https://readwise.io/to_kindle?action=open&asin=B0B7QTX8LL&location=11828)) - The advantage of checking the borrowing rules at runtime instead is that certain memory-safe scenarios are then allowed, where they would’ve been disallowed by the compile-time checks. ([Location 11836](https://readwise.io/to_kindle?action=open&asin=B0B7QTX8LL&location=11836)) - Here is a recap of the reasons to choose Box<T>, Rc<T>, or RefCell<T>: Rc<T> enables multiple owners of the same data; Box<T> and RefCell<T> have single owners. Box<T> allows immutable or mutable borrows checked at compile time; Rc<T> allows only immutable borrows checked at compile time; RefCell<T> allows immutable or mutable borrows checked at runtime. Because RefCell<T> allows mutable borrows checked at runtime, you can mutate the value inside the RefCell<T> even when the RefCell<T> is immutable. ([Location 11847](https://readwise.io/to_kindle?action=open&asin=B0B7QTX8LL&location=11847)) - Mutating the value inside an immutable value is the interior mutability pattern. ([Location 11857](https://readwise.io/to_kindle?action=open&asin=B0B7QTX8LL&location=11857)) - Using RefCell<T> is one way to get the ability to have interior mutability, but RefCell<T> doesn’t get around the borrowing rules completely: the borrow checker in the compiler allows this interior mutability, and the borrowing rules are checked at runtime instead. ([Location 11872](https://readwise.io/to_kindle?action=open&asin=B0B7QTX8LL&location=11872)) - Sometimes during testing a programmer will use a type in place of another type, in order to observe particular behavior and assert that it’s implemented correctly. This placeholder type is called a test double. ([Location 11879](https://readwise.io/to_kindle?action=open&asin=B0B7QTX8LL&location=11879)) - Mock objects are specific types of test doubles that record what happens during a test so you can assert that the correct actions took place. ([Location 11882](https://readwise.io/to_kindle?action=open&asin=B0B7QTX8LL&location=11882)) - We can’t modify the MockMessenger to keep track of the messages because the send method takes an immutable reference to self. ([Location 11970](https://readwise.io/to_kindle?action=open&asin=B0B7QTX8LL&location=11970)) - When creating immutable and mutable references, we use the & and &mut syntax, respectively. With RefCell<T>, we use the borrow and borrow_mut methods, which are part of the safe API that belongs to RefCell<T>. The borrow method returns the smart pointer type Ref<T>, and borrow_mut returns the smart pointer type RefMut<T>. Both types implement Deref, so we can treat them like regular references. ([Location 12017](https://readwise.io/to_kindle?action=open&asin=B0B7QTX8LL&location=12017)) - The RefCell<T> keeps track of how many Ref<T> and RefMut<T> smart pointers are currently active. Every time we call borrow, the RefCell<T> increases its count of how many immutable borrows are active. When a Ref<T> value goes out of scope, the count of immutable borrows goes down by 1. Just like the compile-time borrowing rules, RefCell<T> lets us have many immutable borrows or one mutable borrow at any point in time. ([Location 12024](https://readwise.io/to_kindle?action=open&asin=B0B7QTX8LL&location=12024)) - Choosing to catch borrowing errors at runtime rather than compile time, as we’ve done here, means you’d potentially be finding mistakes in your code later in the development process: possibly not until your code was deployed to production. Also, your code would incur a small runtime performance penalty as a result of keeping track of the borrows at runtime rather than compile time. ([Location 12054](https://readwise.io/to_kindle?action=open&asin=B0B7QTX8LL&location=12054)) - A common way to use RefCell<T> is in combination with Rc<T>. Recall that Rc<T> lets you have multiple owners of some data, but it only gives immutable access to that data. If you have an Rc<T> that holds a RefCell<T>, you can get a value that can have multiple owners and that you can mutate! ([Location 12062](https://readwise.io/to_kindle?action=open&asin=B0B7QTX8LL&location=12062)) - This technique is pretty neat! By using RefCell<T>, we have an outwardly immutable List value. But we can use the methods on RefCell<T> that provide access to its interior mutability so we can modify our data when we need to. The runtime checks of the borrowing rules protect us from data races, and it’s sometimes worth trading a bit of speed for this flexibility in our data structures. ([Location 12111](https://readwise.io/to_kindle?action=open&asin=B0B7QTX8LL&location=12111)) - Rust’s memory safety guarantees make it difficult, but not impossible, to accidentally create memory that is never cleaned up (known as a memory leak). ([Location 12120](https://readwise.io/to_kindle?action=open&asin=B0B7QTX8LL&location=12120)) - Another solution for avoiding reference cycles is reorganizing your data structures so that some references express ownership and some references don’t. As a result, you can have cycles made up of some ownership relationships and some non-ownership relationships, and only the ownership relationships affect whether or not a value can be dropped. ([Location 12214](https://readwise.io/to_kindle?action=open&asin=B0B7QTX8LL&location=12214)) - Strong references are how you can share ownership of an Rc<T> instance. Weak references don’t express an ownership relationship, and their count doesn’t affect when an Rc<T> instance is cleaned up. They won’t cause a reference cycle because any cycle involving some weak references will be broken once the strong reference count of values involved is 0. ([Location 12226](https://readwise.io/to_kindle?action=open&asin=B0B7QTX8LL&location=12226)) - When you call Rc::downgrade, you get a smart pointer of type Weak<T>. Instead of increasing the strong_count in the Rc<T> instance by 1, calling Rc::downgrade increases the weak_count by 1. The Rc<T> type uses weak_count to keep track of how many Weak<T> references exist, similar to strong_count. The difference is the weak_count doesn’t need to be 0 for the Rc<T> instance to be cleaned up. ([Location 12230](https://readwise.io/to_kindle?action=open&asin=B0B7QTX8LL&location=12230)) - Because the value that Weak<T> references might have been dropped, to do anything with the value that a Weak<T> is pointing to you must make sure the value still exists. Do this by calling the upgrade method on a Weak<T> instance, which will return an Option<Rc<T>>. ([Location 12237](https://readwise.io/to_kindle?action=open&asin=B0B7QTX8LL&location=12237)) - Thinking about the relationships another way, a parent node should own its children: if a parent node is dropped, its child nodes should be dropped as well. However, a child should not own its parent: if we drop a child node, the parent should still exist. This is a case for weak references! ([Location 12291](https://readwise.io/to_kindle?action=open&asin=B0B7QTX8LL&location=12291)) - Handling concurrent programming safely and efficiently is another of Rust’s major goals. Concurrent programming, in which different parts of a program execute independently, and parallel programming, in which different parts of a program execute at the same time, are becoming increasingly important as more computers take advantage of their multiple processors. ([Location 12426](https://readwise.io/to_kindle?action=open&asin=B0B7QTX8LL&location=12426)) - For simplicity’s sake, we’ll refer to many of the problems as concurrent rather than being more precise by saying concurrent and/or parallel. If this book were about concurrency and/or parallelism, we’d be more specific. ([Location 12441](https://readwise.io/to_kindle?action=open&asin=B0B7QTX8LL&location=12441)) - Message-passing concurrency, where channels send messages between threads ([Location 12453](https://readwise.io/to_kindle?action=open&asin=B0B7QTX8LL&location=12453)) - Shared-state concurrency, where multiple threads have access to some piece of data ([Location 12454](https://readwise.io/to_kindle?action=open&asin=B0B7QTX8LL&location=12454)) - The Sync and Send traits, which extend Rust’s concurrency guarantees to user-defined types as well as types provided by the standard library ([Location 12455](https://readwise.io/to_kindle?action=open&asin=B0B7QTX8LL&location=12455)) - In most current operating systems, an executed program’s code is run in a process, and the operating system will manage multiple processes at once. Within a program, you can also have independent parts that run simultaneously. The features that run these independent parts are called threads. ([Location 12458](https://readwise.io/to_kindle?action=open&asin=B0B7QTX8LL&location=12458)) - complexity. Because threads can run simultaneously, there’s no inherent guarantee about the order in which parts of your code on different threads will run. This can lead to problems, such as: Race conditions, in which threads are accessing data or resources in an inconsistent order Deadlocks, in which two threads are waiting for each other, preventing both threads from continuing Bugs that only happen in certain situations and are hard to reproduce and fix reliably ([Location 12463](https://readwise.io/to_kindle?action=open&asin=B0B7QTX8LL&location=12463)) - To create a new thread, we call the thread::spawn function and pass it a closure (we talked about closures in Chapter 13) containing the code we want to run in the new thread. ([Location 12475](https://readwise.io/to_kindle?action=open&asin=B0B7QTX8LL&location=12475)) - Note that when the main thread of a Rust program completes, all spawned threads are shut down, whether or not they have finished running. The output from this program might be a little different every time, ([Location 12487](https://readwise.io/to_kindle?action=open&asin=B0B7QTX8LL&location=12487)) - The calls to thread::sleep force a thread to stop its execution for a short duration, allowing a different thread to run. The threads will probably take turns, but that isn’t guaranteed: it depends on how your operating system schedules the threads. In this run, the main thread printed first, even though the print statement from the spawned thread appears first in the code. And even though we told the spawned thread to print until i is 9, it only got to 5 before the main thread shut down. ([Location 12493](https://readwise.io/to_kindle?action=open&asin=B0B7QTX8LL&location=12493)) - We can fix the problem of the spawned thread not running or of it ending prematurely by saving the return value of thread::spawn in a variable. The return type of thread::spawn is JoinHandle<T>. A JoinHandle<T> is an owned value that, when we call the join method on it, will wait for its thread to finish. ([Location 12504](https://readwise.io/to_kindle?action=open&asin=B0B7QTX8LL&location=12504)) - Calling join on the handle blocks the thread currently running until the thread represented by the handle terminates. Blocking a thread means that thread is prevented from performing work or exiting. Because we’ve put the call to join after the main thread’s for loop, ([Location 12525](https://readwise.io/to_kindle?action=open&asin=B0B7QTX8LL&location=12525)) - We’ll often use the move keyword with closures passed to thread::spawn because the closure will then take ownership of the values it uses from the environment, thus transferring ownership of those values from one thread to another. ([Location 12559](https://readwise.io/to_kindle?action=open&asin=B0B7QTX8LL&location=12559)) - Rust infers how to capture v, and because println! only needs a reference to v, the closure tries to borrow v. However, there’s a problem: Rust can’t tell how long the spawned thread will run, so it doesn’t know whether the reference to v will always be valid. ([Location 12590](https://readwise.io/to_kindle?action=open&asin=B0B7QTX8LL&location=12590)) - If Rust allowed us to run this code, there’s a possibility that the spawned thread would be immediately put in the background without running at all. The spawned thread has a reference to v inside, but the main thread immediately drops v, using the drop function we discussed in Chapter 15. Then, when the spawned thread starts to execute, v is no longer valid, so a reference to it is also invalid. ([Location 12606](https://readwise.io/to_kindle?action=open&asin=B0B7QTX8LL&location=12606)) - reason. If we added move to the closure, we would move v into the closure’s environment, and we could no longer call drop on it in the main thread. ([Location 12631](https://readwise.io/to_kindle?action=open&asin=B0B7QTX8LL&location=12631)) - reference. By telling Rust to move ownership of v to the spawned thread, we’re guaranteeing to Rust that the main thread won’t use v anymore. ([Location 12645](https://readwise.io/to_kindle?action=open&asin=B0B7QTX8LL&location=12645)) - One increasingly popular approach to ensuring safe concurrency is message passing, where threads or actors communicate by sending each other messages containing data. ([Location 12652](https://readwise.io/to_kindle?action=open&asin=B0B7QTX8LL&location=12652)) - To accomplish message-sending concurrency, Rust’s standard library provides an implementation of channels. A channel is a general programming concept by which data is sent from one thread to another. ([Location 12656](https://readwise.io/to_kindle?action=open&asin=B0B7QTX8LL&location=12656)) - A channel has two halves: a transmitter and a receiver. The transmitter half is the upstream location where you put the rubber duck into the river, and the receiver half is where the rubber duck ends up downstream. ([Location 12660](https://readwise.io/to_kindle?action=open&asin=B0B7QTX8LL&location=12660)) - We create a new channel using the mpsc::channel function; mpsc stands for multiple producer, single consumer. In short, the way Rust’s standard library implements channels means a channel can have multiple sending ends that produce values but only one receiving end that consumes those values. ([Location 12676](https://readwise.io/to_kindle?action=open&asin=B0B7QTX8LL&location=12676)) - The abbreviations tx and rx are traditionally used in many fields for transmitter and receiver, respectively, so we name our variables as such to indicate each end. ([Location 12684](https://readwise.io/to_kindle?action=open&asin=B0B7QTX8LL&location=12684)) - Again, we’re using thread::spawn to create a new thread and then using move to move tx into the closure so that the spawned thread owns tx. The spawned thread needs to own the transmitter to be able to send messages through the channel. ([Location 12701](https://readwise.io/to_kindle?action=open&asin=B0B7QTX8LL&location=12701)) - we’re calling unwrap to panic in case of an error. But in a real application, we would handle it properly: ([Location 12707](https://readwise.io/to_kindle?action=open&asin=B0B7QTX8LL&location=12707)) - The receiver has two useful methods: recv and try_recv. We’re using recv, short for receive, which will block the main thread’s execution and wait until a value is sent down the channel. Once a value is sent, recv will return it in a Result<T, E>. When the transmitter closes, recv will return an error to signal that no more values will be coming. ([Location 12722](https://readwise.io/to_kindle?action=open&asin=B0B7QTX8LL&location=12722)) - The try_recv method doesn’t block, but will instead return a Result<T, E> immediately: an Ok value holding a message if one is available and an Err value if there aren’t any messages this time. Using try_recv is useful if this thread has other work to do while waiting for messages: we could write a loop that calls try_recv every so often, handles a message if one is available, and otherwise does other work for a little while until checking again. ([Location 12727](https://readwise.io/to_kindle?action=open&asin=B0B7QTX8LL&location=12727)) - once the value has been sent to another thread, that thread could modify or drop it before we try to use the value again. ([Location 12757](https://readwise.io/to_kindle?action=open&asin=B0B7QTX8LL&location=12757)) - The send function takes ownership of its parameter, and when the value is moved the receiver takes ownership of it. ([Location 12767](https://readwise.io/to_kindle?action=open&asin=B0B7QTX8LL&location=12767)) - In the main thread, we’re not calling the recv function explicitly anymore: instead, we’re treating rx as an iterator. For each value received, we’re printing it. When the channel is closed, iteration will end. ([Location 12790](https://readwise.io/to_kindle?action=open&asin=B0B7QTX8LL&location=12790)) - Another method would be for multiple threads to access the same shared data. Consider this part of the slogan from the Go language documentation again: “Do not communicate by sharing memory.” ([Location 12834](https://readwise.io/to_kindle?action=open&asin=B0B7QTX8LL&location=12834)) - value. Shared-memory concurrency is like multiple ownership: multiple threads can access the same memory location at the same time. ([Location 12838](https://readwise.io/to_kindle?action=open&asin=B0B7QTX8LL&location=12838)) - Mutex is an abbreviation for mutual exclusion, as in a mutex allows only one thread to access some data at any given time. To access the data in a mutex, a thread must first signal that it wants access by asking to acquire the mutex’s lock. The lock is a data structure that is part of the mutex that keeps track of who currently has exclusive access to the data. Therefore, the mutex is described as guarding the data it holds via the locking system. ([Location 12844](https://readwise.io/to_kindle?action=open&asin=B0B7QTX8LL&location=12844)) - Mutexes have a reputation for being difficult to use because you have to remember two rules: You must attempt to acquire the lock before using the data. When you’re done with the data that the mutex guards, you must unlock the data so other threads can acquire the lock. ([Location 12849](https://readwise.io/to_kindle?action=open&asin=B0B7QTX8LL&location=12849)) - The call to lock would fail if another thread holding the lock panicked. In that case, no one would ever be able to get the lock, so we’ve chosen to unwrap and have this thread panic if we’re in that situation. ([Location 12873](https://readwise.io/to_kindle?action=open&asin=B0B7QTX8LL&location=12873)) - After we’ve acquired the lock, we can treat the return value, named num in this case, as a mutable reference to the data inside. The type system ensures that we acquire a lock before using the value in m. The type of m is Mutex<i32>, not i32, so we must call lock to be able to use the i32 value. We can’t forget; the type system won’t let us access the inner i32 otherwise. ([Location 12876](https://readwise.io/to_kindle?action=open&asin=B0B7QTX8LL&location=12876)) - unwrap. The MutexGuard smart pointer implements Deref to point at our inner data; the smart pointer also has a Drop implementation that releases the lock automatically when a MutexGuard goes out of scope, which happens at the end of the inner scope ([Location 12885](https://readwise.io/to_kindle?action=open&asin=B0B7QTX8LL&location=12885)) - The error message states that the counter value was moved in the previous iteration of the loop. Rust is telling us that we can’t move the ownership of lock counter into multiple threads. ([Location 12930](https://readwise.io/to_kindle?action=open&asin=B0B7QTX8LL&location=12930)) - Wow, that error message is very wordy! Here’s the important part to focus on: `Rc<Mutex<i32>>` cannot be sent between threads safely ❶. The compiler is also telling us the reason why: the trait `Send` is not implemented for `Rc<Mutex<i32>>` ❷. ([Location 12966](https://readwise.io/to_kindle?action=open&asin=B0B7QTX8LL&location=12966)) - Unfortunately, Rc<T> is not safe to share across threads. When Rc<T> manages the reference count, it adds to the count for each call to clone and subtracts from the count when each clone is dropped. But it doesn’t use any concurrency primitives to make sure that changes to the count can’t be interrupted by another thread. This could lead to wrong counts—subtle bugs that could in turn lead to memory leaks or a value being dropped before we’re done with it. ([Location 12971](https://readwise.io/to_kindle?action=open&asin=B0B7QTX8LL&location=12971)) - Fortunately, Arc<T> is a type like Rc<T> that is safe to use in concurrent situations. The a stands for atomic, meaning it’s an atomically reference-counted type. Atomics are an additional kind of concurrency primitive that we won’t cover in detail here: see the standard library documentation for std::sync::atomic for more details. At this point, you just need to know that atomics work like primitive types but are safe to share across threads. ([Location 12978](https://readwise.io/to_kindle?action=open&asin=B0B7QTX8LL&location=12978)) - You could also use this program’s structure to do more complicated operations than just incrementing a counter. Using this strategy, you can divide a calculation into independent parts, split those parts across threads, and then use a Mutex<T> to have each thread update the final result with its part. ([Location 13011](https://readwise.io/to_kindle?action=open&asin=B0B7QTX8LL&location=13011)) - You might have noticed that counter is immutable, but we could get a mutable reference to the value inside it; this means Mutex<T> provides interior mutability, as the Cell family does. In the same way we used RefCell<T> in Chapter 15 to allow us to mutate contents inside an Rc<T>, we use Mutex<T> to mutate contents inside an Arc<T>. ([Location 13019](https://readwise.io/to_kindle?action=open&asin=B0B7QTX8LL&location=13019)) - Similarly, Mutex<T> comes with the risk of creating deadlocks. These occur when an operation needs to lock two resources and two threads have each acquired one of the locks, causing them to wait for each other forever. ([Location 13028](https://readwise.io/to_kindle?action=open&asin=B0B7QTX8LL&location=13028)) - The Send marker trait indicates that ownership of values of the type implementing Send can be transferred between threads. Almost every Rust type is Send, but there are some exceptions, including Rc<T>: this cannot be Send because if you cloned an Rc<T> value and tried to transfer ownership of the clone to another thread, both threads might update the reference count at the same time. For this reason, Rc<T> is implemented for use in single-threaded situations where you don’t want to pay the thread-safe performance penalty. ([Location 13044](https://readwise.io/to_kindle?action=open&asin=B0B7QTX8LL&location=13044)) - The Sync marker trait indicates that it is safe for the type implementing Sync to be referenced from multiple threads. In other words, any type T is Sync if &T (an immutable reference to T) is Send, meaning the reference can be sent safely to another thread. Similar to Send, primitive types are Sync, and types composed entirely of types that are Sync are also Sync. ([Location 13060](https://readwise.io/to_kindle?action=open&asin=B0B7QTX8LL&location=13060)) - Because types that are made up of Send and Sync traits are automatically also Send and Sync, we don’t have to implement those traits manually. As marker traits, they don’t even have any methods to implement. They’re just useful for enforcing invariants related to concurrency. Manually implementing these traits involves implementing unsafe Rust code. ([Location 13076](https://readwise.io/to_kindle?action=open&asin=B0B7QTX8LL&location=13076)) - Object-oriented programming (OOP) is a way of modeling programs. Objects as a programmatic concept were introduced in the programming language Simula in the 1960s. Those objects influenced Alan Kay’s programming architecture in which objects pass messages to each other. To describe this architecture, he coined the term object-oriented programming ([Location 13102](https://readwise.io/to_kindle?action=open&asin=B0B7QTX8LL&location=13102)) - and by some of these definitions Rust is object oriented but by others it is not. ([Location 13105](https://readwise.io/to_kindle?action=open&asin=B0B7QTX8LL&location=13105)) - OOP languages share certain common characteristics, namely objects, encapsulation, and inheritance. ([Location 13112](https://readwise.io/to_kindle?action=open&asin=B0B7QTX8LL&location=13112)) - Another aspect commonly associated with OOP is the idea of encapsulation, which means that the implementation details of an object aren’t accessible to code using that object. Therefore, the only way to interact with an object is through its public API; code using the object shouldn’t be able to reach into the object’s internals and change data or behavior directly. ([Location 13126](https://readwise.io/to_kindle?action=open&asin=B0B7QTX8LL&location=13126)) - The struct is marked pub so that other code can use it, but the fields within the struct remain private. This is important in this case because we want to ensure that whenever a value is added or removed from the list, the average is also updated. ([Location 13143](https://readwise.io/to_kindle?action=open&asin=B0B7QTX8LL&location=13143)) - The public methods add, remove, and average are the only ways to access or modify data in an instance of AveragedCollection. When an item is added to list using the add method or removed using the remove method, the implementations of each call the private update_average method that handles updating the average field as well. ([Location 13162](https://readwise.io/to_kindle?action=open&asin=B0B7QTX8LL&location=13162)) - We leave the list and average fields private so there is no way for external code to add or remove items to or from the list field directly; otherwise, the average field might become out of sync when the list changes. ([Location 13168](https://readwise.io/to_kindle?action=open&asin=B0B7QTX8LL&location=13168)) - Because we’ve encapsulated the implementation details of the struct AveragedCollection, we can easily change aspects, such as the data structure, in the future. ([Location 13173](https://readwise.io/to_kindle?action=open&asin=B0B7QTX8LL&location=13173)) - Inheritance is a mechanism whereby an object can inherit elements from another object’s definition, thus gaining the parent object’s data and behavior without you having to define them again. ([Location 13187](https://readwise.io/to_kindle?action=open&asin=B0B7QTX8LL&location=13187)) - If a language must have inheritance to be object oriented, then Rust is not such a language. There is no way to define a struct that inherits the parent struct’s fields and method implementations without using a macro. ([Location 13189](https://readwise.io/to_kindle?action=open&asin=B0B7QTX8LL&location=13189)) - You would choose inheritance for two main reasons. One is for reuse of code: you can implement particular behavior for one type, and inheritance enables you to reuse that implementation for a different type. ([Location 13192](https://readwise.io/to_kindle?action=open&asin=B0B7QTX8LL&location=13192)) - The other reason to use inheritance relates to the type system: to enable a child type to be used in the same places as the parent type. This is also called polymorphism, which means that you can substitute multiple objects for each other at runtime if they share certain characteristics. ([Location 13201](https://readwise.io/to_kindle?action=open&asin=B0B7QTX8LL&location=13201)) - To many people, polymorphism is synonymous with inheritance. But it’s actually a more general concept that refers to code that can work with data of multiple types. For inheritance, those types are generally subclasses. Rust instead uses generics to abstract over different possible types and trait bounds to impose constraints on what those types must provide. This is sometimes called bounded parametric polymorphism. ([Location 13205](https://readwise.io/to_kindle?action=open&asin=B0B7QTX8LL&location=13205)) - Inheritance has recently fallen out of favor as a programming design solution in many programming languages because it’s often at risk of sharing more code than necessary. Subclasses shouldn’t always share all characteristics of their parent class but will do so with inheritance. ([Location 13210](https://readwise.io/to_kindle?action=open&asin=B0B7QTX8LL&location=13210)) - A trait object points to both an instance of a type implementing our specified trait and a table used to look up trait methods on that type at runtime. We create a trait object by specifying some sort of pointer, such as an & reference or a Box<T> smart pointer, then the dyn keyword, and then specifying the relevant trait. ([Location 13247](https://readwise.io/to_kindle?action=open&asin=B0B7QTX8LL&location=13247)) - We’ve mentioned that, in Rust, we refrain from calling structs and enums “objects” to distinguish them from other languages’ objects. In a struct or enum, the data in the struct fields and the behavior in impl blocks are separated, whereas in other languages, the data and behavior combined into one concept is often labeled an object. ([Location 13255](https://readwise.io/to_kindle?action=open&asin=B0B7QTX8LL&location=13255)) - This works differently from defining a struct that uses a generic type parameter with trait bounds. A generic type parameter can be substituted with only one concrete type at a time, whereas trait objects allow for multiple concrete types to fill in for the trait object at runtime. ([Location 13290](https://readwise.io/to_kindle?action=open&asin=B0B7QTX8LL&location=13290)) - This restricts us to a Screen instance that has a list of components all of type Button or all of type TextField. If you’ll only ever have homogeneous collections, using generics and trait bounds is preferable because the definitions will be monomorphized at compile time to use the concrete types. ([Location 13302](https://readwise.io/to_kindle?action=open&asin=B0B7QTX8LL&location=13302)) - This concept—of being concerned only with the messages a value responds to rather than the value’s concrete type—is similar to the concept of duck typing in dynamically typed languages: if it walks like a duck and quacks like a duck, then it must be a duck! ([Location 13369](https://readwise.io/to_kindle?action=open&asin=B0B7QTX8LL&location=13369)) - The code that results from monomorphization is doing static dispatch, which is when the compiler knows what method you’re calling at compile time. This is opposed to dynamic dispatch, which is when the compiler can’t tell at compile time which method you’re calling. In dynamic dispatch cases, the compiler emits code that at runtime will figure out which method to call. ([Location 13404](https://readwise.io/to_kindle?action=open&asin=B0B7QTX8LL&location=13404)) - When we use trait objects, Rust must use dynamic dispatch. The compiler doesn’t know all the types that might be used with the code that’s using trait objects, so it doesn’t know which method implemented on which type to call. ([Location 13407](https://readwise.io/to_kindle?action=open&asin=B0B7QTX8LL&location=13407)) - The state pattern is an object-oriented design pattern. The crux of the pattern is that we define a set of states a value can have internally. The states are represented by a set of state objects, and the value’s behavior changes based on its state. ([Location 13414](https://readwise.io/to_kindle?action=open&asin=B0B7QTX8LL&location=13414)) - The state objects share functionality: in Rust, of course, we use structs and traits rather than objects and inheritance. Each state object is responsible for its own behavior and for governing when it should change into another state. The value that holds a state object knows nothing about the different behavior of the states or when to transition between states. ([Location 13418](https://readwise.io/to_kindle?action=open&asin=B0B7QTX8LL&location=13418)) - The State trait defines the behavior shared by different post states. The state objects are Draft, PendingReview, and Published, and they will all implement the State trait. ([Location 13481](https://readwise.io/to_kindle?action=open&asin=B0B7QTX8LL&location=13481)) - This syntax takes ownership of Box<Self>, invalidating the old state so the state value of the Post can transform into a new state. ([Location 13564](https://readwise.io/to_kindle?action=open&asin=B0B7QTX8LL&location=13564)) - We call the as_ref method on the Option because we want a reference to the value inside the Option rather than ownership of the value. Because state is an Option<Box<dyn State>>, when we call as_ref, an Option<&Box<dyn State>> is returned. If we didn’t call as_ref, we would get an error because we can’t move state out of the borrowed &self of the function parameter. ([Location 13649](https://readwise.io/to_kindle?action=open&asin=B0B7QTX8LL&location=13649)) - You may have been wondering why we didn’t use an enum with the different possible post states as variants. That’s certainly a possible solution; try it and compare the end results to see which you prefer! One disadvantage of using an enum is that every place that checks the value of the enum will need a match expression or similar to handle every possible variant. This could get more repetitive than this trait object solution. ([Location 13693](https://readwise.io/to_kindle?action=open&asin=B0B7QTX8LL&location=13693)) - If we were to create an alternative implementation that didn’t use the state pattern, we might instead use match expressions in the methods on Post or even in the main code that checks the state of the post and changes behavior in those places. That would mean we would have to look in several places to understand all the implications of a post being in the published state! This would only increase the more states we added: each of those match expressions would need another arm. ([Location 13704](https://readwise.io/to_kindle?action=open&asin=B0B7QTX8LL&location=13704)) - With the state pattern, the Post methods and the places we use Post don’t need match expressions, and to add a new state, we would only need to add a new struct and implement the trait methods on that one struct. ([Location 13709](https://readwise.io/to_kindle?action=open&asin=B0B7QTX8LL&location=13709)) - The implementation using the state pattern is easy to extend to add more functionality. To see the simplicity of maintaining code that uses the state pattern, try a few of these suggestions: Add a reject method that changes the post’s state from PendingReview back to Draft. Require two calls to approve before the state can be changed to Published. Allow users to add text content only when a post is in the Draft state. Hint: have the state object responsible for what might change about the content but not responsible for modifying the Post. ([Location 13712](https://readwise.io/to_kindle?action=open&asin=B0B7QTX8LL&location=13712)) - Patterns are a special syntax in Rust for matching against the structure of types, both complex and simple. Using patterns in conjunction with match expressions and other constructs gives you more control over a program’s control flow. A pattern consists of some combination of the following: Literals Destructured arrays, enums, structs, or tuples Variables Wildcards Placeholders ([Location 13854](https://readwise.io/to_kindle?action=open&asin=B0B7QTX8LL&location=13854)) - we use patterns in the arms of match expressions. Formally, match expressions are defined as the keyword match, a value to match on, and one or more match arms that consist of a pattern and an expression to run if the value matches that arm’s pattern, ([Location 13873](https://readwise.io/to_kindle?action=open&asin=B0B7QTX8LL&location=13873)) - One requirement for match expressions is that they need to be exhaustive in the sense that all possibilities for the value in the match expression must be accounted for. One way to ensure you’ve covered every possibility is to have a catch-all pattern for the last arm: for example, a variable name matching any value can never fail and thus covers every remaining case. ([Location 13889](https://readwise.io/to_kindle?action=open&asin=B0B7QTX8LL&location=13889)) - The particular pattern _ will match anything, but it never binds to a variable, so it’s often used in the last match arm. ([Location 13893](https://readwise.io/to_kindle?action=open&asin=B0B7QTX8LL&location=13893)) - use if let expressions mainly as a shorter way to write the equivalent of a match that only matches one case. Optionally, if let can have a corresponding else containing code to run if the pattern in the if let doesn’t match. ([Location 13899](https://readwise.io/to_kindle?action=open&asin=B0B7QTX8LL&location=13899)) - Every time you’ve used a let statement like this you’ve been using patterns, ([Location 13991](https://readwise.io/to_kindle?action=open&asin=B0B7QTX8LL&location=13991)) - In statements like let x = 5; with a variable name in the PATTERN slot, the variable name is just a particularly simple form of a pattern. Rust compares the expression against the pattern and assigns any names it finds. So, in the let x = 5; example, x is a pattern that means “bind what matches here to the variable x.” Because the name x is the whole pattern, this pattern effectively means “bind everything to the variable x, whatever the value is.” ([Location 13996](https://readwise.io/to_kindle?action=open&asin=B0B7QTX8LL&location=13996)) - Patterns come in two forms: refutable and irrefutable. Patterns that will match for any possible value passed are irrefutable. An example would be x in the statement let x = 5; because x matches anything and therefore cannot fail to match. Patterns that can fail to match for some possible value are refutable. An example would be Some(x) in the expression if let Some(x) = a_value because if the value in the a_value variable is None rather than Some, the Some(x) pattern will not match. ([Location 14057](https://readwise.io/to_kindle?action=open&asin=B0B7QTX8LL&location=14057)) - Function parameters, let statements, and for loops can only accept irrefutable patterns because the program cannot do anything meaningful when values don’t match. ([Location 14064](https://readwise.io/to_kindle?action=open&asin=B0B7QTX8LL&location=14064)) - The if let and while let expressions accept refutable and irrefutable patterns, but the compiler warns against irrefutable patterns because, by definition, they’re intended to handle possible failure: the functionality of a conditional is in its ability to perform differently depending on success or failure. ([Location 14066](https://readwise.io/to_kindle?action=open&asin=B0B7QTX8LL&location=14066)) - Named variables are irrefutable patterns that match any value, and we’ve used them many times in this book. However, there is a complication when you use named variables in match expressions. Because match starts a new scope, variables declared as part of a pattern inside the match expression will shadow those with the same name outside the match construct, as is the case with all variables. ([Location 14135](https://readwise.io/to_kindle?action=open&asin=B0B7QTX8LL&location=14135)) - The pattern in the second match arm ❹ introduces a new variable named y that will match any value inside a Some value. Because we’re in a new scope inside the match expression, this is a new y variable, not the y we declared at the beginning with the value 10 ❷. This new y binding will match any value inside a Some, which is what we have in x. Therefore, this new y binds to the inner value of the Some in x. That value is 5, so the expression for that arm executes and prints Matched, y = 5. ([Location 14157](https://readwise.io/to_kindle?action=open&asin=B0B7QTX8LL&location=14157)) - To create a match expression that compares the values of the outer x and y, rather than introducing a shadowed variable, we would need to use a match guard conditional instead. ([Location 14176](https://readwise.io/to_kindle?action=open&asin=B0B7QTX8LL&location=14176)) - This code creates the variables a and b that match the values of the x and y fields of the p struct. ([Location 14226](https://readwise.io/to_kindle?action=open&asin=B0B7QTX8LL&location=14226)) - pattern: using the _ pattern (which you’ve seen), using the _ pattern within another pattern, using a name that starts with an underscore, or using .. to ignore remaining parts of a value. ([Location 14344](https://readwise.io/to_kindle?action=open&asin=B0B7QTX8LL&location=14344)) - This code will completely ignore the value 3 passed as the first argument, and will print This code only uses the y parameter: 4. ([Location 14357](https://readwise.io/to_kindle?action=open&asin=B0B7QTX8LL&location=14357)) - In most cases when you no longer need a particular function parameter, you would change the signature so it doesn’t include the unused parameter. Ignoring a function parameter can be especially useful in cases when, for example, you’re implementing a trait when you need a certain type signature but the function body in your implementation doesn’t need one of the parameters. You then avoid getting a compiler warning about unused function parameters, as you would if you used a name instead. ([Location 14359](https://readwise.io/to_kindle?action=open&asin=B0B7QTX8LL&location=14359)) - We can also use _ inside another pattern to ignore just part of a value, for example, when we want to test for only part of a value but have no use for the other parts in the corresponding code we want to run. ([Location 14364](https://readwise.io/to_kindle?action=open&asin=B0B7QTX8LL&location=14364)) - Note that there is a subtle difference between using only _ and using a name that starts with an underscore. The syntax _x still binds the value to the variable, whereas _ doesn’t bind at all. ([Location 14410](https://readwise.io/to_kindle?action=open&asin=B0B7QTX8LL&location=14410)) - We’ll receive an error because the s value will still be moved into _s, which prevents us from using s again. However, using the underscore by itself doesn’t ever bind to the value. ([Location 14419](https://readwise.io/to_kindle?action=open&asin=B0B7QTX8LL&location=14419)) - With values that have many parts, we can use the .. syntax to use specific parts and ignore the rest, avoiding the need to list underscores for each ignored value. The .. pattern ignores any parts of a value that we haven’t explicitly matched in the rest of the pattern. ([Location 14431](https://readwise.io/to_kindle?action=open&asin=B0B7QTX8LL&location=14431)) - The variable name second doesn’t mean anything special to Rust, so we get a compiler error because using .. in two places like this is ambiguous. ([Location 14482](https://readwise.io/to_kindle?action=open&asin=B0B7QTX8LL&location=14482)) - A match guard is an additional if condition, specified after the pattern in a match arm, that must also match for that arm to be chosen. Match guards are useful for expressing more complex ideas than a pattern alone allows. ([Location 14485](https://readwise.io/to_kindle?action=open&asin=B0B7QTX8LL&location=14485)) - This code will now print Default case, x = Some(5). The pattern in the second match arm doesn’t introduce a new variable y that would shadow the outer y, meaning we can use the outer y in the match guard. Instead of specifying the pattern as Some(y), which would have shadowed the outer y, we specify Some(n). This creates a new variable n that doesn’t shadow anything because there is no n variable outside the match. ([Location 14521](https://readwise.io/to_kindle?action=open&asin=B0B7QTX8LL&location=14521)) - The at operator @ lets us create a variable that holds a value at the same time we’re testing that value for a pattern match. ([Location 14561](https://readwise.io/to_kindle?action=open&asin=B0B7QTX8LL&location=14561)) - Rust has a second language hidden inside it that doesn’t enforce these memory safety guarantees: it’s called unsafe Rust and works just like regular Rust, but gives us extra superpowers. ([Location 14612](https://readwise.io/to_kindle?action=open&asin=B0B7QTX8LL&location=14612)) - Another reason Rust has an unsafe alter ego is that the underlying computer hardware is inherently unsafe. If Rust didn’t let you do unsafe operations, you couldn’t do certain tasks. Rust needs to allow you to do low-level systems programming, such as directly interacting with the operating system or even writing your own operating system. Working with low-level systems programming is one of the goals of the language. ([Location 14619](https://readwise.io/to_kindle?action=open&asin=B0B7QTX8LL&location=14619)) - To switch to unsafe Rust, use the unsafe keyword and then start a new block that holds the unsafe code. You can take five actions in unsafe Rust that you can’t in safe Rust, which we call unsafe superpowers. Those superpowers include the ability to: Dereference a raw pointer Call an unsafe function or method Access or modify a mutable static variable Implement an unsafe trait Access fields of unions ([Location 14624](https://readwise.io/to_kindle?action=open&asin=B0B7QTX8LL&location=14624)) - It’s important to understand that unsafe doesn’t turn off the borrow checker or disable any of Rust’s other safety checks: if you use a reference in unsafe code, it will still be checked. The unsafe keyword only gives you access to these five features that are then not checked by the compiler for memory safety. ([Location 14631](https://readwise.io/to_kindle?action=open&asin=B0B7QTX8LL&location=14631)) - Unsafe Rust has two new types called raw pointers that are similar to references. As with references, raw pointers can be immutable or mutable and are written as *const T and *mut T, respectively. The asterisk isn’t the dereference operator; it’s part of the type name. In the context of raw pointers, immutable means that the pointer can’t be directly assigned to after being dereferenced. ([Location 14650](https://readwise.io/to_kindle?action=open&asin=B0B7QTX8LL&location=14650)) - Different from references and smart pointers, raw pointers: Are allowed to ignore the borrowing rules by having both immutable and mutable pointers or multiple mutable pointers to the same location Aren’t guaranteed to point to valid memory Are allowed to be null Don’t implement any automatic cleanup ([Location 14654](https://readwise.io/to_kindle?action=open&asin=B0B7QTX8LL&location=14654)) - Recall that we can create raw pointers in safe code, but we can’t dereference raw pointers and read the data being pointed to. ([Location 14679](https://readwise.io/to_kindle?action=open&asin=B0B7QTX8LL&location=14679)) - Creating a pointer does no harm; it’s only when we try to access the value that it points at that we might end up dealing with an invalid value. ([Location 14687](https://readwise.io/to_kindle?action=open&asin=B0B7QTX8LL&location=14687)) - the code would not have compiled because Rust’s ownership rules don’t allow a mutable reference at the same time as any immutable references. ([Location 14692](https://readwise.io/to_kindle?action=open&asin=B0B7QTX8LL&location=14692)) - With all of these dangers, why would you ever use raw pointers? One major use case is when interfacing with C code, as you’ll see in the next section. Another case is when building up safe abstractions that the borrow checker doesn’t understand. ([Location 14695](https://readwise.io/to_kindle?action=open&asin=B0B7QTX8LL&location=14695)) - The second type of operation you can perform in an unsafe block is calling unsafe functions. Unsafe functions and methods look exactly like regular functions and methods, but they have an extra unsafe before the rest of the definition. ([Location 14699](https://readwise.io/to_kindle?action=open&asin=B0B7QTX8LL&location=14699)) - Sometimes your Rust code might need to interact with code written in another language. For this, Rust has the keyword extern that facilitates the creation and use of a Foreign Function Interface (FFI), which is a way for a programming language to define functions and enable a different (foreign) programming language to call those functions. ([Location 14808](https://readwise.io/to_kindle?action=open&asin=B0B7QTX8LL&location=14808)) - Within the extern "C" block, we list the names and signatures of external functions from another language we want to call. The "C" part defines which application binary interface (ABI) the external function uses: the ABI defines how to call the function at the assembly level. ([Location 14823](https://readwise.io/to_kindle?action=open&asin=B0B7QTX8LL&location=14823)) - We can also use extern to create an interface that allows other languages to call Rust functions. Instead of creating a whole extern block, we add the extern keyword and specify the ABI to use just before the fn keyword for the relevant function. We also need to add a #[no_mangle] annotation to tell the Rust compiler not to mangle the name of this function. Mangling is when a compiler changes the name we’ve given a function to a different name that contains more information for other parts of the compilation process to consume but is less human readable. ([Location 14829](https://readwise.io/to_kindle?action=open&asin=B0B7QTX8LL&location=14829)) - global variables are called static variables. ([Location 14846](https://readwise.io/to_kindle?action=open&asin=B0B7QTX8LL&location=14846)) - A subtle difference between constants and immutable static variables is that values in a static variable have a fixed address in memory. Using the value will always access the same data. Constants, on the other hand, are allowed to duplicate their data whenever they’re used. Another difference is that static variables can be mutable. Accessing and modifying mutable static variables is unsafe. ([Location 14858](https://readwise.io/to_kindle?action=open&asin=B0B7QTX8LL&location=14858)) - We can use unsafe to implement an unsafe trait. A trait is unsafe when at least one of its methods has some invariant that the compiler can’t verify. We declare that a trait is unsafe by adding the unsafe keyword before trait and marking the implementation of the trait as unsafe too, ([Location 14879](https://readwise.io/to_kindle?action=open&asin=B0B7QTX8LL&location=14879)) - If we implement a type that contains a type that is not Send or Sync, such as raw pointers, and we want to mark that type as Send or Sync, we must use unsafe. Rust can’t verify that our type upholds the guarantees that it can be safely sent across threads or accessed from multiple threads; therefore, we need to do those checks manually and indicate as such with unsafe. ([Location 14893](https://readwise.io/to_kindle?action=open&asin=B0B7QTX8LL&location=14893)) - The final action that works only with unsafe is accessing fields of a union. A union is similar to a struct, but only one declared field is used in a particular instance at one time. Unions are primarily used to interface with unions in C code. Accessing union fields is unsafe because Rust can’t guarantee the type of the data currently being stored in the union instance. ([Location 14900](https://readwise.io/to_kindle?action=open&asin=B0B7QTX8LL&location=14900)) - Using unsafe to use one of the five superpowers just discussed isn’t wrong or even frowned upon, but it is trickier to get unsafe code correct because the compiler can’t help uphold memory safety. When you have a reason to use unsafe code, you can do so, and having the explicit unsafe annotation makes it easier to track down the source of problems when they occur. ([Location 14906](https://readwise.io/to_kindle?action=open&asin=B0B7QTX8LL&location=14906)) - Associated types connect a type placeholder with a trait such that the trait method definitions can use these placeholder types in their signatures. The implementor of a trait will specify the concrete type to be used instead of the placeholder type for the particular implementation. ([Location 14916](https://readwise.io/to_kindle?action=open&asin=B0B7QTX8LL&location=14916)) - The type Item is a placeholder, and the next method’s definition shows that it will return values of type Option<Self::Item>. Implementors of the Iterator trait will specify the concrete type for Item, and the next method will return an Option containing a value of that concrete type. ([Location 14931](https://readwise.io/to_kindle?action=open&asin=B0B7QTX8LL&location=14931)) - The difference is that when using generics, as in Listing 19-13, we must annotate the types in each implementation; because we can also implement Iterator<String> for Counter or any other type, we could have multiple implementations of Iterator for Counter. In other words, when a trait has a generic parameter, it can be implemented for a type multiple times, changing the concrete types of the generic type parameters each time. ([Location 14951](https://readwise.io/to_kindle?action=open&asin=B0B7QTX8LL&location=14951)) - A great example of a situation where this technique is useful is with operator overloading, in which you customize the behavior of an operator (such as +) in particular situations. ([Location 14971](https://readwise.io/to_kindle?action=open&asin=B0B7QTX8LL&location=14971)) - The new part is Rhs=Self: this syntax is called default type parameters. The Rhs generic type parameter (short for “right-hand side”) defines the type of the rhs parameter in the add method. ([Location 14999](https://readwise.io/to_kindle?action=open&asin=B0B7QTX8LL&location=14999)) - To add Millimeters and Meters, we specify impl Add<Meters> to set the value of the Rhs type parameter instead of using the default of Self. You’ll use default type parameters in two main ways: To extend a type without breaking existing code To allow customization in specific cases most users won’t need ([Location 15026](https://readwise.io/to_kindle?action=open&asin=B0B7QTX8LL&location=15026)) - Nothing in Rust prevents a trait from having a method with the same name as another trait’s method, nor does Rust prevent you from implementing both traits on one type. It’s also possible to implement a method directly on the type with the same name as methods from traits. When calling methods with the same name, you’ll need to tell Rust which one you want to use. ([Location 15040](https://readwise.io/to_kindle?action=open&asin=B0B7QTX8LL&location=15040)) - Because the fly method takes a self parameter, if we had two types that both implement one trait, Rust could figure out which implementation of a trait to use based on the type of self. ([Location 15085](https://readwise.io/to_kindle?action=open&asin=B0B7QTX8LL&location=15085)) - To disambiguate and tell Rust that we want to use the implementation of Animal for Dog as opposed to the implementation of Animal for some other type, we need to use fully qualified syntax. ([Location 15133](https://readwise.io/to_kindle?action=open&asin=B0B7QTX8LL&location=15133)) - For associated functions that aren’t methods, there would not be a receiver: there would only be the list of other arguments. You could use fully qualified syntax everywhere that you call functions or methods. ([Location 15154](https://readwise.io/to_kindle?action=open&asin=B0B7QTX8LL&location=15154)) - Sometimes you might write a trait definition that depends on another trait: for a type to implement the first trait, you want to require that type to also implement the second trait. You would do this so that your trait definition can make use of the associated items of the second trait. The trait your trait definition is relying on is called a supertrait of your trait. ([Location 15160](https://readwise.io/to_kindle?action=open&asin=B0B7QTX8LL&location=15160)) - Newtype is a term that originates from the Haskell programming language. There is no runtime performance penalty for using this pattern, and the wrapper type is elided at compile time. ([Location 15225](https://readwise.io/to_kindle?action=open&asin=B0B7QTX8LL&location=15225)) - Because Kilometers and i32 are the same type, we can add values of both types and we can pass Kilometers values to functions that take i32 parameters. However, using this method, we don’t get the type-checking benefits that we get from the newtype pattern discussed earlier. ([Location 15296](https://readwise.io/to_kindle?action=open&asin=B0B7QTX8LL&location=15296)) - The type alias helps in two ways: it makes code easier to write and it gives us a consistent interface across all of std::io. Because it’s an alias, it’s just another Result<T, E>, which means we can use any methods that work on Result<T, E> with it, as well as special syntax like the ? operator. ([Location 15348](https://readwise.io/to_kindle?action=open&asin=B0B7QTX8LL&location=15348)) - Rust has a special type named ! that’s known in type theory lingo as the empty type because it has no values. We prefer to call it the never type because it stands in the place of the return type when a function will never return. ([Location 15354](https://readwise.io/to_kindle?action=open&asin=B0B7QTX8LL&location=15354)) - This code is read as “the function bar returns never.” Functions that return never are called diverging functions. We can’t create values of the type !, so bar can never possibly return. ([Location 15359](https://readwise.io/to_kindle?action=open&asin=B0B7QTX8LL&location=15359)) - Rust needs to know certain details about its types, such as how much space to allocate for a value of a particular type. This leaves one corner of its type system a little confusing at first: the concept of dynamically sized types. Sometimes referred to as DSTs or unsized types, these types let us write code using values whose size we can know only at runtime. ([Location 15411](https://readwise.io/to_kindle?action=open&asin=B0B7QTX8LL&location=15411)) - So what do we do? In this case, you already know the answer: we make the types of s1 and s2 a &str rather than a str. Recall from “String Slices” on page 79 that the slice data structure just stores the starting position and the length of the slice. So, although a &T is a single value that stores the memory address of where the T is located, a &str is two values: the address of the str and its length. ([Location 15426](https://readwise.io/to_kindle?action=open&asin=B0B7QTX8LL&location=15426)) - A trait bound on ?Sized means “T may or may not be Sized” and this notation overrides the default that generic types must have a known size at compile time. The ?Trait syntax with this meaning is only available for Sized, not any other traits. ([Location 15457](https://readwise.io/to_kindle?action=open&asin=B0B7QTX8LL&location=15457)) - Functions coerce to the type fn (with a lowercase f), not to be confused with the Fn closure trait. The fn type is called a function pointer. Passing functions with function pointers will allow you to use functions as arguments to other functions. ([Location 15470](https://readwise.io/to_kindle?action=open&asin=B0B7QTX8LL&location=15470)) - Unlike closures, fn is a type rather than a trait, so we specify fn as the parameter type directly rather than declaring a generic type parameter with one of the Fn traits as a trait bound. ([Location 15496](https://readwise.io/to_kindle?action=open&asin=B0B7QTX8LL&location=15496)) - As an example of where you could use either a closure defined inline or a named function, let’s look at a use of the map method provided by the Iterator trait in the standard library. To use the map function to turn a vector of numbers into a vector of strings, we could use a closure, like this: ([Location 15505](https://readwise.io/to_kindle?action=open&asin=B0B7QTX8LL&location=15505)) - Closures are represented by traits, which means you can’t return closures directly. In most cases where you might want to return a trait, you can instead use the concrete type that implements the trait as the return value of the function. However, you can’t do that with closures because they don’t have a concrete type that is returnable; you’re not allowed to use the function pointer fn as a return type, for example. ([Location 15533](https://readwise.io/to_kindle?action=open&asin=B0B7QTX8LL&location=15533)) - The term macro refers to a family of features in Rust: declarative macros with macro_rules! and three kinds of procedural macros: Custom #[derive] macros that specify code added with the derive attribute used on structs and enums Attribute-like macros that define custom attributes usable on any item Function-like macros that look like function calls but operate on the tokens specified as their argument We’ll talk about each of these in turn, but first, let’s look at why we even need macros when we already have functions. ([Location 15558](https://readwise.io/to_kindle?action=open&asin=B0B7QTX8LL&location=15558)) - Fundamentally, macros are a way of writing code that writes other code, which is known as metaprogramming. ([Location 15567](https://readwise.io/to_kindle?action=open&asin=B0B7QTX8LL&location=15567)) - All of these macros expand to produce more code than the code you’ve written manually. ([Location 15570](https://readwise.io/to_kindle?action=open&asin=B0B7QTX8LL&location=15570)) - A function signature must declare the number and type of parameters the function has. Macros, on the other hand, can take a variable number of parameters: we can call println!("hello") with one argument or println!("hello {}", name) with two arguments. Also, macros are expanded before the compiler interprets the meaning of the code, so a macro can, for example, implement a trait on a given type. A function can’t, because it gets called at runtime and a trait needs to be implemented at compile time. ([Location 15574](https://readwise.io/to_kindle?action=open&asin=B0B7QTX8LL&location=15574)) - The downside to implementing a macro instead of a function is that macro definitions are more complex than function definitions because you’re writing Rust code that writes Rust code. ([Location 15578](https://readwise.io/to_kindle?action=open&asin=B0B7QTX8LL&location=15578)) - The most widely used form of macros in Rust is the declarative macro. These are also sometimes referred to as “macros by example,” “macro_rules! macros,” or just plain “macros.” At their core, declarative macros allow you to write something similar to a Rust match expression. ([Location 15584](https://readwise.io/to_kindle?action=open&asin=B0B7QTX8LL&location=15584)) - The #[macro_export] annotation ❶ indicates that this macro should be made available whenever the crate in which the macro is defined is brought into scope. ([Location 15618](https://readwise.io/to_kindle?action=open&asin=B0B7QTX8LL&location=15618)) - We then start the macro definition with macro_rules! and the name of the macro we’re defining without the exclamation mark ❷. ([Location 15620](https://readwise.io/to_kindle?action=open&asin=B0B7QTX8LL&location=15620)) - The structure in the vec! body is similar to the structure of a match expression. Here we have one arm with the pattern ( $( $x:expr ),* ), followed by => and the block of code associated with this pattern ❸. ([Location 15623](https://readwise.io/to_kindle?action=open&asin=B0B7QTX8LL&location=15623)) - First we use a set of parentheses to encompass the whole pattern. We use a dollar sign ($) to declare a variable in the macro system that will contain the Rust code matching the pattern. The dollar sign makes it clear this is a macro variable as opposed to a regular Rust variable. ([Location 15633](https://readwise.io/to_kindle?action=open&asin=B0B7QTX8LL&location=15633)) - The comma following $() indicates that a literal comma separator character could optionally appear after the code that matches the code in $(). The * specifies that the pattern matches zero or more of whatever precedes the *. ([Location 15639](https://readwise.io/to_kindle?action=open&asin=B0B7QTX8LL&location=15639)) - The second form of macros is the procedural macro, which acts more like a function (and is a type of procedure). Procedural macros accept some code as an input, operate on that code, and produce some code as an output rather than matching against patterns and replacing the code with other code as declarative macros do. The three kinds of procedural macros are custom derive, attribute-like, and function-like, and all work in a similar fashion. ([Location 15659](https://readwise.io/to_kindle?action=open&asin=B0B7QTX8LL&location=15659)) - The quote! macro lets us define the Rust code that we want to return. ([Location 15824](https://readwise.io/to_kindle?action=open&asin=B0B7QTX8LL&location=15824)) - Function-like macros define macros that look like function calls. Similarly to macro_rules! macros, they’re more flexible than functions; for example, they can take an unknown number of arguments. However, macro_rules! macros can only be defined using the match-like syntax we discussed in “Declarative Macros with macro_rules! for General Metaprogramming” on page 449. Function-like macros take a TokenStream parameter, and their definition manipulates that TokenStream using Rust code as the other two types of procedural macros do. An example of a function-like macro is an sql! macro ([Location 15882](https://readwise.io/to_kindle?action=open&asin=B0B7QTX8LL&location=15882)) - The two main protocols involved in web servers are Hypertext Transfer Protocol (HTTP) and Transmission Control Protocol (TCP). Both protocols are request-response protocols, meaning a client initiates requests and a server listens to the requests and provides a response to the client. The contents of those requests and responses are defined by the protocols. ([Location 15928](https://readwise.io/to_kindle?action=open&asin=B0B7QTX8LL&location=15928)) - TCP is the lower-level protocol that describes the details of how information gets from one server to another but doesn’t specify what that information is. ([Location 15933](https://readwise.io/to_kindle?action=open&asin=B0B7QTX8LL&location=15933)) - HTTP builds on top of TCP by defining the contents of the requests and responses. It’s technically possible to use HTTP with other protocols, but in the vast majority of cases, HTTP sends its data over TCP. ([Location 15934](https://readwise.io/to_kindle?action=open&asin=B0B7QTX8LL&location=15934)) - A single stream represents an open connection between the client and the server. A connection is the name for the full request and response process in which a client connects to the server, the server generates a response, and the server closes the connection. ([Location 15971](https://readwise.io/to_kindle?action=open&asin=B0B7QTX8LL&location=15971)) - The first line is the request line that holds information about what the client is requesting. ([Location 16063](https://readwise.io/to_kindle?action=open&asin=B0B7QTX8LL&location=16063)) - The next part of the request line is /, which indicates the uniform resource identifier (URI) the client is requesting: a URI is almost, but not quite, the same as a uniform resource locator (URL). ([Location 16068](https://readwise.io/to_kindle?action=open&asin=B0B7QTX8LL&location=16068)) - The last part is the HTTP version the client uses, and then the request line ends in a CRLF sequence. (CRLF stands for carriage return and line feed, which are terms from the typewriter days!) The CRLF sequence can also be written as \r\n, where \r is a carriage return and \n is a line feed. ([Location 16073](https://readwise.io/to_kindle?action=open&asin=B0B7QTX8LL&location=16073)) - The first line is a status line that contains the HTTP version used in the response, a numeric status code that summarizes the result of the request, and a reason phrase that provides a text description of the status code. After the CRLF sequence are any headers, another CRLF sequence, and the body of the response. ([Location 16091](https://readwise.io/to_kindle?action=open&asin=B0B7QTX8LL&location=16091)) - A thread pool is a group of spawned threads that are waiting and ready to handle a task. When the program receives a new task, it assigns one of the threads in the pool to the task, and that thread will process the task. ([Location 16310](https://readwise.io/to_kindle?action=open&asin=B0B7QTX8LL&location=16310)) - Each of the threads in the pool will pop off a request from this queue, handle the request, and then ask the queue for another request. With this design, we can process up to N requests concurrently, where N is the number of threads. ([Location 16318](https://readwise.io/to_kindle?action=open&asin=B0B7QTX8LL&location=16318)) - The F type parameter is the one we’re concerned with here; the T type parameter is related to the return value, and we’re not concerned with that. We can see that spawn uses FnOnce as the trait bound on F. ([Location 16437](https://readwise.io/to_kindle?action=open&asin=B0B7QTX8LL&location=16437)) - We still use the () after FnOnce ❶ because this FnOnce represents a closure that takes no parameters and returns the unit type (). Just like function definitions, the return type can be omitted from the signature, but even if we have no parameters, we still need the parentheses. ([Location 16456](https://readwise.io/to_kindle?action=open&asin=B0B7QTX8LL&location=16456))