EN

Rust Programming Language

by RepeatMe Open Decks

Ownership, borrowing, traits, error handling and Cargo, following The Rust Programming Language book. Source: Adrian Sieber and The Rust Project Developers, https://github.com/ad-si/Coding-Flashcards (MIT), converted for RepeatMe.

code rust programming
557 cards

What's inside

How do you create a new package named hello_world?
cargo new hello_world
What’s the command to run a package?
cargo run
What is the command to build a project without producing a binary to
check for errors?
cargo check
How do we include the input/output functionality from the standard
library?
use std::io;
Which command can you use to build documentation provided by all of
your dependencies locally and open it in your browser?
cargo doc --open
How do you create an infinite loop?
loop {
…
}
How do you exit a loop forcibly?
break;
What does the _ after Err mean?

let guess: u32 = match guess.trim().parse() {
Ok(num) => num,
Err(_) => continue,
];
The underscore _ means that we don’t care about the
value that is inside the Err. It will not be bound to any
variable.
What’s the command to tell the program to go to the next iteration of
the loop?
continue;
How do you make a new variable shadow the first?
You can declare a new variable with the same name as a previous
variable. Rustaceans say that the first variable is shadowed by the
second, which means that the second variable is what the compiler will
see when you use the name of the variable.
What is the possible bit range of integers?
8 to 128 bit

Length
Signed
Unsigned

8-bit
i8
u8

16-bit
i16
u16

32-bit
i32
u32

64-bit
i64
u64

128-bit
i128
u128

arch
isize
usize
In this table of integer types, what do the isize or
usize variants (in the arch row) stand for?

Length
Signed
Unsigned

8-bit
i8
u8

16-bit
i16
u16

32-bit
i32
u32

64-bit
i64
u64

128-bit
i128
u128

arch
isize
usize
Architecture. The isize and usize types
depend on the architecture of the computer your program is running on,
which is denoted in the table as “arch”: 64 bits if you’re on a 64-bit
architecture and 32 bits if you’re on a 32-bit architecture.
What’s the integer type variant that gets the size of the bits of the
architecture the program is running on?

(64 bits if you’re on a 64-bit architecture and 32 bits if you’re on
a 32-bit architecture)
The variant with ‘size’ after its integer type (signed or unsigned,
respectively).

Length
Signed
Unsigned

arch
isize
usize
How do you create a signed integer with 128 bits named
hello_world?
let hello_world: i128;
How do you create an unsigned integer with 128 bits named
hello_world?
let hello_world: u128;
What is the range of numbers that can be stored using signed two’s
complement representation (as a function of \(n\))?
Each signed variant can store numbers from \([(-2^{n-1}), (2^{n-1}-1)]\).
What is the range of numbers that can be stored using unsigned two’s
complement representation (as a function of \(n\))?
Each unsigned variant can store numbers from \(0\) to \(2^{n}-1\).
What is the range of number that an i8 signed integer
can store?
It can store numbers from \(-128\)
to \(127\).
What is the range of number that a u8 unsigned integer
can store?
It can store numbers from \(0\) to
\(255\).
How to write a number literal that is an 8 bit
unsigned integer with the value 57?
Simply by adding to the literal a type suffix, like so:
57u8
How do you write a hexadecimal literal?
0 and the number separated by x

For example:

assert_eq!(0x2A, 42);
How can you make decimal literals more readable?
Using _ as the thousands separator.

For example:

let x = 28_222;
How do you make an octal base number literal?
0 and the number separated by an o

For example:

assert_eq!(0o77, 63);
How do you write a binary literal?
0 and the number separated by b

For example:

assert_eq!(0b101, 5);
What’s the only integer type suitable for Byte representation?
u8 (e.g. b'A')
How do you represent a Byte literal?
b, and then its ASCII char
(0-255) enclosed by single quotes.

For example:

b'A'
What is the primary situation in which you’d use isize
or usize?

Length
Signed
Unsigned

8-bit
i8
u8

16-bit
i16
u16

32-bit
i32
u32

64-bit
i64
u64

128-bit
i128
u128

arch
isize
usize
When indexing some sort of collection.
How to write an unsigned floating point literal?
You can’t. All floating-point types are signed.
What’s the default floating point type?
f64

Reason: It’s roughly the same speed as f32 but capable
of more precision.

fn main() {
let x = 2.0; // f64
let y: f32 = 3.0; // f32
}
What’s the precision degree of f64?
Double precision

f32 is single precision and both are represented
according to the IEEE-754 standard.
How do you define a boolean and how much space in memory does it
occupy?
Booleans are one byte in size. The Boolean type in Rust is specified
using bool.

fn main() {
let t = true;
let f: bool = false; // With explicit type annotation
}
How much space in memory does a char occupy?
Rust’s char type is four bytes in size and
represents a Unicode Scalar Value, which means it can represent a lot
more than just ASCII.

fn main() {
let c = 'z';
let z: char = 'Z'; // With explicit type annotation
let heart_eyed_cat = '\u{1F63B}';
}
What’s the difference between how to define strings and how to define
char literals?
Character literals (char) are specified with single
quotes ('), while string literals (&str)
use double quotes (")

fn main() {
let c = 'z';
let s = "z";
// With explicit type annotation
let c: char = 'Z';
let s: &str = "Z";
}
What are compound types?
Compound types can group multiple values into one type.
What primitive compound types does Rust have?
Rust has 2 primitive compound types:

Tuples:

fn main() {
let tup: (i32, f64, u8) = (500, 6.4, 1);
}

Arrays:

fn main() {
let arr: [u32; 10] = [1, 2, 3, 4, 5, 6, 7, 8, 9, 10];
}
How can you create a tuple?
A tuple is created by writing a comma-separated list of values inside
parentheses:

fn main() {
let tup: (i32, f64, u8) = (500, 6.4, 1);
}
How can we get the individual values out of a tuple? (2 ways)
Destructuring via pattern matching:

fn main() {
let tup = (500, 6.4, 1);
let (x, y, z) = tup;
println!("The value of y is: {y}");
}

Dot notation with indexes:

fn main() {
let x: (i32, f64, u8) = (500, 6.4, 1);
let five_hundred = x.0;
let six_point_four = x.1;
let one = x.2;
}
What’s the name of a tuple without any value? When does it come
up?
The tuple without any values has the special name
“unit”. This value and its corresponding type are both
written () and represent an empty value or an empty return
type.

Expressions implicitly return the unit value if they don’t return any
other value.
What can we say about the size of arrays?
Unlike arrays in some other languages, arrays in Rust have a fixed
length.

fn main() {
let a = [1, 2, 3, 4, 5];
}
Name 2 good uses of arrays
Arrays are useful in the following situations:

When you want your data allocated on the stack
rather than the heap.

When you want to ensure you always have a fixed number of
elements
.
What can we say about arrays in relation to vectors?
Arrays aren’t as flexible as vectors

A vector is allowed to grow or shrink in
size


Vectors are collection type provided by the standard library

If you’re unsure whether to use an array or a vector, chances are you
should use a vector.
Name 2 ways to initialize an array.
Define each element individually:

let a: [i32; 5] = [1, 2, 3, 4, 5];

Define them all at once:

let a = [3; 5];

Which is same as:

let a = [3, 3, 3, 3, 3];
What’s the difference between statements and expressions?
Statements are instructions that perform some action and do not
return a value. Expressions evaluate to a resulting value.
What’s the difference between arguments and parameters?
Parameters are the variable definitions in the top area of the
function, arguments are the concrete values
Statement or expression?

Creating a variable and assigning a value to it with the
let keyword.

fn main() {
let y = 6;
}
Statement
Statement or expression?

Function definitions
Statement

fn main() {
let y = 6;
}
Statement or expression?

Calling a function
Expression
Statement or expression?

Calling a macro
Expression
Statement or expression?

A new scope block created with curly brackets
Expression

For example:

fn main() {
let y = {
let x = 3;
x + 1
};

println!("The value of y is: {y}");
}

y = 4, in this case
fn main() {
let y = {
let x = 3;
x + 1
};

println!("The value of y is: {y}");
}

Why doesn’t x + 1 have a semicolon at the end?
It is an expression and not a statement. 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.
How do we declare a function’s return type?
With an arrow:

fn five() -> i32 {
5
}
Statement or expression?

if … { … } else { … }
Expression.

Because if is an expression, we can use it on the right
side of a let statement to assign the outcome to a
variable:

fn main() {
let condition = true;
let number = if condition { 5 } else { 6 };

println!("The value of number is: {number}");
}
What does continue; in a loop do?
It makes the program skip over any remaining code in this iteration
of the loop and go to the next iteration.
Inside a loop, how can you return a value OUT of the loop so you can
use it after the break; expression you use to stop the
loop?
One can simply add the desired expression to be returned after the
break:

fn main() {
let mut counter = 0;

let result = loop {
counter += 1;
if counter == 10 {
break counter * 2;
}
}

println!("The result is {result}");
}
If you have loops within loops, how can you break / continue a
specific loop instead of the innermost loop?
With loop labels. Loop labels must begin with a
single quote.

fn main() {
let mut count = 0;
'counting_up: loop {
println!("Count = {}", count);
let mut remaining = 10;
loop {
println!("Remaining = {}", remaining);
if remaining == 9 {
break;
}
if count == 2 {
break 'counting_up;
}
remaining -= 1;
}
count += 1;
}
println!("End count = {}", count);
}
We want to use while to loop the program three times,
counting down each time, and then, after the loop, print a message and
exit. Fill out the black blank.

fn main() {
let mut number = 3;

########## {
println!("{number}!");
number -= 1;
}

println!("LIFTOFF !!!");
}
while number != 0
fn main() {
let arr = [10, 20, 30, 40, 50];
let mut index = 0;
while index < 5 {
println!("The value is: {}", arr[index]);
index += 1;
}
}

Looping through a collection like this is a bad idea. Give 2 reasons
why.
It’s error prone

It’s slow (due to bound checking)

Detailed Explanation:

It’s error prone because it could cause the program to panic if the
index value or test condition are 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, the code would
panic.

It’s slow because the compiler adds runtime code to perform the
conditional check of whether the index is within the bounds of the array
on every iteration through the loop.
fn main() {
let arr = [10, 20, 30, 40, 50];
let mut index = 0;
while index < 5 {
println!("The value is: {}", arr[index]);
index += 1;
}
}

What is a better and more concise alternative to loop over the
array?
To use a for loop:

fn main() {
let arr = [10, 20, 30, 40, 50];

for element in arr {
println!("The value is: {}", element);
}
}

The safety and conciseness of for loops make them the
most commonly used loop construct in Rust.
Even in situations in which you want to run some code a certain
number of times, as in the countdown example that used a
while loop, most Rustaceans would use a for
loop.

fn main() {
let mut number = 3;
while number != 0 {
println!("number: {}" number);
number -= 1;
}
println!("LIFTOFF !!!");
}

How would you do this with a for loop instead?
Using a Range, provided by the standard library:

fn main() {
for number in (1..4).rev() {
println!("number: {}", number);
}
println!("LIFTOFF !!!");
}
What are the 3 rules of ownership?
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.
Why is a string literal not the best fit for some things?
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.

Another is that not every string value can be known when we write
our code.

For example, what if we want to take user input and store it? For
these situations, Rust has a second string type,
String.
What is the difference between the String type and the
string literal?
The String 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.

let mut greet = String::from("Hello");
greet.push_str(", world!"); // Appends a literal to a String
println!("{}", greet); // Prints "Hello, world!"
With a String type, besides the contents of the string,
which data are created and where are they stored?
A String is made up of three parts (shown on the left):

Pointer to the memory that holds the contents of the string

Length

Capacity

This group of data is stored on the stack. On the right is the memory
on the heap that holds the contents.
let s1 = String::from("Hello");
let s2 = s1;

What happens in terms of the heap and stack when we assign
s1 to s2 in line 2?
The String data is copied, meaning we copy:

Pointer

Length

Capacity

that are on the stack.

We do not copy the data on the heap that the pointer
refers to.
let s1 = String::from("Hello");
let s2 = s1;

println!("{}, world!", s1);

What happens to s1 in this case?
Compile-time error!

In this example, we would say that s1 was moved into
s2, as Rust considers s1 as no longer
valid.

Because Rust invalidates the first variable, instead of calling it a
shallow copy, it’s known as a move. So what actually happens is shown
here:
let s2 = s1.clone();

What could be a red flag?
This works just fine and explicitly produces the behavior where
the heap data does get copied.

And yet, 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.
How do you reference an object?
With an ampersand:

fn main() {
let s1 = String::from("Hello");
let len = calculate_length(&s1);
println!("The length of '{}' is {}", s1, len);
}

fn calculate_length(s: &String) -> usize {
s.len()
}

These ampersands represent references, and they allow you to refer to
some value without taking ownership of it.
What is one guarantee that a reference has and a conventional pointer
doesn’t?
Unlike a pointer, a reference is guaranteed to point to a valid value
of a particular type for the life of that reference.
How do we call the action of creating a
reference
?
Borrowing
What is not possible by default when borrowing?
Mutating.

Just as variables are immutable by default, so are references. We’re
not allowed to modify something we have a reference to.
fn main() {
let s = String::from("Hello");
change(&s);
}

fn change(some_string: &String) {
some_string.push_str(", world");
}

How can you make this reference mutable?
Put &mut s as parameter instead of
&s and &mut String as parameter type
instead of &String.

fn main() {
let mut s = String::from("Hello");
change(&mut s);
}

fn change(some_string: &mut String) {
some_string.push_str(", world");
}
What’s the restrictions that mutable references have?
If you have a mutable reference to a value, you can have no other
(mutable or otherwise) references to that value.

This will fail, for example:

let mut s = String::from("Hello");

let r1 = &mut s;
let r2 = &mut s;

println!("{}, {}", r1, r2);

This as well:

let mut s = String::from("Hello");

let r1 = &s; // No problem
let r2 = &s; // No problem
let r3 = &mut s; // BIG PROBLEM

println!("{}, {}, and {}", r1, r2, r3);
What’s the benefit of the restriction preventing multiple mutable
references to the same data at the same time?
The benefit of having this restriction is that Rust can
prevent data races at compile time.

It 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.
What are the 3 preconditions for a data race to occur?
A data race 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

(Note: A data race is similar to a race condition)
What’s a workaround we can use to allow multiple mutable references
to the same data?
We can use curly brackets to create a new scope, allowing for
multiple mutable references, just not simultaneous ones:

fn main() {
let mut s: String = String::from("Hello");
{
let r1: &mut String = &mut s;
// r1 goes out of scope here,
}
// So we can make a new reference with no problems
let r2: &mut String = &mut s;
}
fn main() {
let mut s: String = String::from("Hello");

let r1: &String = &s;
let r2: &String = &s;
let r3: &String = &mut s;

println!("{}, {}, and {}", r1, r2, r3);
}

What’s going to happen with this code?
Compile-time error!

Since Rust enforces a similar rule as the restriction preventing
multiple mutable references to the same data at the same time for
combining mutable and immutable references, this code results in an
error:

let mut s = String::from("Hello");

let rl = &s; // No problem
let r2 = &s; // No problem
let r3 = &mut s; // BIG PROBLEM

println!("{}, {}, and {}", r1, r2, r3);
Why are mutable references not allowed to co-exist with other
references while multiple immutable references are allowed?
Because users of an immutable reference don’t expect the value to
suddenly change out from under them! However, multiple immutable
references are allowed because no one who is just reading the data has
the ability to affect anyone else’s reading of the data.
fn main()
let mut s: String = String::from("Hello");

let r1: &String = &s;
let r2: &String = &s;
println!("{} and {}", r1, r2);

let r3: &mut String = &mut s;
println!("{}", r3);
}

Why will this not trigger compile-time errors involving mutable and
immutable rules?
Because a reference’s scope starts from where it is introduced and
continues through the last time that reference is used.
Therefore, this code will compile because the last usage of the
immutable references, the println!, occurs before the
mutable reference is introduced. These scopes don’t overlap, so this
code is allowed

let mut s = String::from("Hello");

let r1 = &s; // No problem
let r2 = &s; // No problem
println!("{} and {}", r1, r2);
// Variables r1 and r2 will not be used after this point

let r3 = &mut s; // No problem
println!("{}", r3);

See also: Non-Lexical Lifetimes or NLL
What’s a “dangling pointer”?
It’s a pointer pointing to an invalid value.

In other words: it’s 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.
What guarantee do we have regarding “dangling pointers”?
In Rust, 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.

This will not compile:

fn main() {
let reference_to_nothing = dangle();
}

// Returns a reference to a String
fn dangle() -> &String {
let s = String::from("Hello"); // s is a new String

&s // Return a reference to the String `s`
}
// Here, s goes out of scope, and is dropped.
// Its memory goes away.
// Danger!
What’s the problem with this code?

fn dangle() -> &String {
let s = String::from("Hello");
&s
}

fn main() {
let reference_to_nothing = dangle();
}

What could be a solution?
// Returns a reference to a String
fn dangle() -> &String {
let s = String::from("Hello"); // s is a new String

&s // Returns a reference to the String `s`
}
// Here, s goes out of scope, and is dropped.
// Its memory goes away.
// Danger!

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. That’s no good! Rust won’t let us do
this. The solution here is to return the String directly:

fn no_dangle() -> String {
let s = String::from("Hello");
s
}

This works without any problems. Ownership is moved out, and nothing
is deallocated.
What are the 2 rules of references that are enforced by the
compiler?
At any given time, you can have either one mutable reference or any
number of immutable references.

References must always be valid (and not ‘dangling’).
What’s the Slice type?
Slices let you reference a contiguous sequence of elements in
a collection
rather than the whole collection.
What are the Slice type’s ownership properties?
A slice is a kind of reference, so it does not have ownership.
What’s a string Slice? What does it look like in action (on a string
named s)?
A string slice is a reference to part of a
String
, and it looks like this:

let s = String::from("Hello world");

let hello = &s[0..5];
let world = &s[6..11];

Rather than a reference to the entire String,
hello is a reference to a portion of the
String, specified in the extra [0..5] bit.
How do you create slices?
You create slices using a range within brackets by specifying
[starting_index..ending_index], where
starting_index is the first position in the slice and
ending_index is one more than the last position in the
slice.

let s = String::from("Hello world");

let hello = &s[0..5];
let world = &s[6..11];
let s = String::from("Hello");

let slice1 = &s[0..2];
let slice2 = &s[..2];

What can you say about those 2 values?
With Rust’s .. range syntax, if you want to start at
index zero, you can drop the value before the two periods.

In other words, they are equal.
let s = String::from("Hello");
let len = s.len();

let slice1 = &s[3..len];
let slice2 = &s[3..];

What can you say about those 2 values?
With Rust’s .. range syntax, if your slice includes the
last byte of the String, you can drop the trailing number.

In other words, they are equal.
let s = String::from("Hello");
let len = s.len();

let slice = &s[0.. len];
let slice = &s[..];

What can you say about those 2 values?
With Rust’s .. range syntax, you can drop both values to
take a slice of the entire string.

In other words, they are equal.
What’s a possible error inducing operation on string slice range
indices?
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
multi-byte character, your program will exit with an error.

let greeting = "Hello, \u{1F30D}!"; // The globe emoji is a multi-byte character
let sliced = &greeting[0..9]; // Panics because it's slicing through it
fn first_word(s: &String) -> &str {
let bytes = s.as_bytes();

for (i, &item) in bytes.iter().enumerate() {
if item == b' ' {
return &s[0..i];
}
}

&s[..]
}

fn main() {
let mut s = String::from("Hello world");
let word = first_word(&s);
s.clear();
println!("The first word is: {}", word);
}

What’s going to happen with this code?
Compile-time error!

Detailed Explanation:

If we have an immutable reference to something, we cannot also take a
mutable reference.

Because clear() needs to truncate the
String, it needs to get a mutable reference. The
println! after the call to clear() uses the
reference in word, so the immutable reference must still be
active at that 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!
fn first_word(s: &String) -> &str {

How can we improve upon this function signature?
Knowing that you can take slices of literals and String
values leads us to an improvement on the function signature:

fn first_word(s: &str) -> &str {

That’s how a more experienced Rustacean would write the signature
shown instead because it allows us to use the same function first_word
on both &String values and &str values.
let word = first_word(&my_string[..]);

What is equal to &my_string[..]?
&my_string

let word = first_word(&my_string[..]);

// `first_word` also works on references to `String`s,
// which are equivalent to whole slices of `String`s

let word = first_word(&my_string);
How do you output assembly?
You can use Cargo’s cargo rustc command to send
arguments to rustc directly:

cargo rustc -- --emit asm
ls target/debug/deps/<crate_name>-<hash>.s
How do you output optimized assembly?
You can use Cargo’s cargo rustc command to send
arguments to rustc directly, for optimized assembly:

cargo rustc --release -- --emit asm
ls target/release/deps/<crate_name>-<hash>.s
What can you do if you see multiple
<crate_name>-<hash>-<hash>.rcgu.s files
instead of a single <crate_name>-<hash>.s file
when outputting assembly?
Disable incremental compilation by setting the environment variable
CARGO_INCREMENTAL=0
What can you do if you just want to look at the assembly output
instead of saving it, e.g. to judge if it’s well-optimized?
An easy option is to check out rust.godbolt.org.

(Don’t forget to add -O to the compiler options
box.)
let a = [1, 2, 3, 4, 5];
let slice = &a[1..3];
assert_eq!(slice, &[2, 3]);

What type does this slice have?
This slice has the type &[i32].

It works the same way as string slices do, by storing a reference to
the first element and a length. You’ll use this kind of slice for all
sorts of other collections.
How do we use a struct after we’ve defined it?

struct User {
active: bool,
username: String,
email: String,
sign_in_count: u64,
}
We create an instance by stating the name of the struct and then add
curly brackets containing key: value pairs, where the keys
are the names of the fields and the values are the data we want to store
in those fields.

fn main() {
let user1 = User {
email: String::from("someone@example.com"),
username: String::from("someusername123"),
active: true,
sign_in_count: 1,
};
}
let mut user1 = User {
email: String::from("someone@example.com"),
username: String::from("someusername123"),
active: true,
sign_in_count: 1,
};

How do we access this user’s email address or change its value?
We use dot notation:

fn main() {
let mut user1 = User {
email: String::from("someone@example.com"),
username: String::from("someusername123"),
active: true,
sign_in_count: 1,
};
user1.email = String::from("another.email@example.com");
};

Note:

The entire instance must be mutable. Rust doesn’t allow us to mark only
certain fields as mutable.
fn build_user(email: String, username: String) -> User {
User {
email: email,
username: username,
active: true,
sign_in_count: 1,
}
}

How can we somewhat shorten this?
Using the field init shorthand syntax.

Because the parameter names and the struct field names can sometimes
be exactly the same, we can use the field init shorthand syntax to make
it so that it behaves exactly the same but doesn’t have the
repetition.

fn build_user(email: String, username: String) -> User {
User {
email,
username,
active: true,
sign_in_count: 1,
}
}
fn main() {
// …

let user2 = User {
active: user1.active,
username: user1.username,
email: String::from("another@example.com"),
sign_in_count: user1.sign_in_count,
};
}

How do we shorten all these values in user2 taken
straight from user1?
With 2 dots, a.k.a the struct update syntax.

It’s often useful to create a new instance of a struct that includes
most of the values from another instance, but changes
some.

fn main() {
// …

let user2 = User {
email: String::from("another@example.com"),
..user1
};
}

Notes:

It’s only 2 dots, not 3

The syntax 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.
let mut user1 = User {
email: String::from("someone@example.com").
username: String rom("someusername123") ,
active: true,
sign_in_count: 1,
}

fn main() {
// …

let user2 = User {
email: String::from("another@example.com"),
..user1
};
}

What can we say about user1?
In this example, ****we can no longer use user1 after
creating user2**** because the String in the username field
of user1 was moved into user2.

Note that the struct update syntax uses = like an
assignment. This is because it moves the data. If we had given
user2 new String values for both email and username, and
thus only used the active and sign_in_count
values from user1, then user1 would still be
valid after creating user2.
struct Color(i32, i32, i32);
struct Point(i32, i32, i32);

What are these called?
These are structs that look similar to tuples, called tuple
structs
.
What could tuple structs be useful for? (3 use cases)
Tuple structs are useful when:

You want to give the whole tuple a name

Make it a different type from other tuples

Naming each field as in a regular struct would be verbose or
redundant.

struct Color(i32, i32, i32);
struct Point(i32, i32, i32);

fn main() {
let black = Color(0, 0, 0);
let origin = Point(0, 0, 0);
}

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.
struct Color(i32, i32, i32);
struct Point(i32, i32, i32);

fn main() {
let black = Color(0, 0, 0);
let origin = Point(0, 0, 0);
}

Can Color and Point here be
interchangeable?
No.

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.
Which type of structs are destructurable?
Both structs and tuple structs.

struct Point {
x: i32,
y: i32,
}

fn main() {
let p = Point { x: 0, y: 7 };
let Point { x: a, y: b } = p;
assert_eq!(0, a);
assert_eq!(7, b);
}
With which type of structs can you use a . followed by
the index to access an individual value?
With both structs and tuple structs.
What are unit-like structs?
They are structs that don’t have any fields. These are called
unit-like structs because they behave similarly to ().

struct AlwaysEqual;

fn main() {
let subject = AlwaysEqual;
}

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.
struct Rectangle {
width: u32,
height: u32,
}

fn main() {
let rect1 = Rectangle {
width: 30,
height: 50,
};
println!("rect1 is {}", rect1);
}

Why will this not print?
With structs, Rust doesn’t try to guess what we want, and structs
don’t have a provided implementation of Display to use with
println! and the {} placeholder.
println!("rect1 is {:?}", rect1);

What does putting the specifier :? inside the curly
brackets change?
Putting the specifier :? inside the curly brackets tells
println! we want to use an output format called
Debug (instead of the default Display).

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.
struct Rectangle {
width: u32,
height: u32,
}

fn main() {
let rect1 = Rectangle {
width: 30,
height: 50,
};

println!("rect1 is {:?}", rect1);
}

What’s missing for this to print?
Adding the outer attribute #[derive(Debug)] just before
the struct definition.

Rust does include functionality to print out debugging information,
but we have to explicitly opt-in to make that functionality available
for our struct.

#[derive(Debug)]
struct Rectangle {
width: u32,
height: u32,
}

fn main() {
let rect1 = Rectangle {
width: 30,
height: 50,
};

println!("rect1 is {:?}", rect1);
}
println!("rect1 is {:?}", rect1);

Running `target/debug/rectangles`
rect1 is Rectangle { width: 30, height: 50 }
When we have larger structs, in order to have output that’s a bit
easier to read, what can we do?
We can use {:#?} instead of {:?} in the
println! string. In this example, using the
{:#?} style will output:

Running `target/debug/rectangles`
rect1 is Rectangle {
width: 30,
height: 50,
}
What’s another way to print out a value using the Debug
format besides using println! with {:?} or
{:#?}?
Using the dbg! macro.

#[derive(Debug)]
struct Rectangle {
width: u32,
height: u32,
}

fn main() {
let scale = 2;
let rect1 = Rectangle {
width: dbg!(30 * scale),
height: 50,
};
dbg!(&rect1);
}

$ cargo run
Compiling rectangles v0.1.0 (file:///projects/rectangles)
Finished dev [unoptimized + debuginfo] target(s) in 0.61s
Running `target/debug/rectangles`
[src/main.rs:10] 30 * scale = 60
[src/main.rs:14] &rect1 = Rectangle {
width: 60,
height: 50,
}
let arr = [1, 2, 3, 4, 5];

How can we slice 2 and 3 out of
arr?
let a = [1, 2, 3, 4, 5];
let slice = &a[1..3];
What’s similar between methods and functions?
They are declared with the fn keyword and a name

They can have parameters and a return value

They contain some code that’s run when the method is called from
somewhere else
What’s different between methods and functions?
Unlike functions, methods are

Defined within the context of a struct (or an enum or a
trait object)

Their first parameter can be self, which represents the instance of
the struct the method is being called on
How do we define the function area within the context of
Rectangle?
We start an implementation block for Rectangle.
Everything within this impl block will be associated with
the Rectangle type. Then we change the first (and in this case, only)
parameter to be self.

struct Rectangle {
width: u32,
height: u32,
}

impl Rectangle {
fn area(&self) -> u32 {
self.width * self.height
}
}
What is &self (in method syntax) actually short
for?
The &self is actually short for
self: &Self.

Note:

We still need to use the & in front of the self
shorthand to indicate 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.
When would we have a method that takes ownership of the instance by
using just self (instead of &self or
&mut self)?
It is rare! This technique is usually used when the
method transforms self into something else and you want to
prevent the caller from using the original instance
after the transformation.
Can you give a method the same name as one of the struct’s field?
Yes.

For example, we can define a method on Rectangle also
named width:

struct Rectangle {
width: u32,
height: u32,
}

impl Rectangle {
fn width(&self) -> bool {
self.width > 0
}
}
Does rust implement getter methods to struct fields?
No.

Sometimes, 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. Rust does
not implement these getters 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.
In C and C++, two different operators are used for calling methods:
you use . if you’re calling a method on the object directly
and -> if you’re calling the method on a pointer to the
object and need to dereference the pointer first. In other words, if
object is a pointer, object->something() is similar to
(*object).something().

What about Rust?
Rust doesn’t have an equivalent to the -> operator.
Instead, Rust has what is called automatic referencing and
dereferencing
.

In other words, the following are the same:

p1.distance(&p2);
(&p1).distance(&p2);

Note:

this automatic referencing behavior works because methods have a clear
receiver-the type of self. Given the receiver and name of a
method, Rust can figure out definitively whether the method is reading
(&self), mutating (&mut self), or
consuming (self).
What are associated functions?
All functions defined within an impl block are called
associated functions because they’re associated with the type named
after the impl.

struct Rectangle {
width: u32,
height: u32,
}

impl Rectangle {
fn area(&self) -> u32 {
self.width * self.height
}
}
What are associated functions that aren’t methods
and what’s a common use for them?
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 (such as
String::from function that’s defined on the
String type).

Associated functions that aren’t methods are often used for
constructors that will return a new instance of the
struct
. These are often called new, but new isn’t a special
name and isn’t built into the language.

struct Rectangle {
width: u32,
height: u32,
}

impl Rectangle {
fn unit() -> Rectangle {
Rectangle {
width: 1,
height: 1,
}
}
}

let unitRect = Rectangle::unit();
impl Rectangle {
fn square(size: u32) -> Self {
Self {
width: size,
height: size,
}
}
}

What is the Self keywords in the return type?
The Self keywords in the return type and in the body of
the function are aliases for the type that appears after the
impl keyword
, which in this case is
Rectangle.
impl Rectangle {
fn square(size: u32) -> Self {
Self {
width: size,
height: size,
}
}
}

How do we call this function with size of 3?
To call this associated function, we use the ::
syntax with the struct name
:

let sq = Rectangle::square(3);
What is the :: syntax used for?
The :: syntax is used for both associated functions:

impl Rectangle {
fn square(size: u32) -> Self {
Self {
width: size,
height: size,
}
}
}

let sq = Rectangle::square(3);

… and namespaces created by modules:

use std::io;

io::stdin()
.read_line(&mut guess)
.expect("Failed to read line");
What is the numerical limit on impl blocks of
structs?
None.

Each struct is allowed to have multiple impl blocks.

For example;

impl Rectangle {
fn area(&self) -> u32 {
self.width * self.height
}

fn can_hold(&self, other: &Rectangle) -> bool {
self.width > other.width &&
self.height > other.height
}
}

is equivalent to:

impl Rectangle {
fn area(&self) -> u32 {
self.width * self.height
}
}

impl Rectangle {
fn can_hold(&self, other: &Rectangle) -> bool {
self.width > other.width &&
self.height > other.height
}
}
What are enumerations (enums)?
Enums allow you to define a type by enumerating its possible
variants. In other words, they give you a way of saying a value
is one of a possible set of values
.
enum IpAddrKind {
V4,
V6,
}

How do we create instances of these 2 variants?
With the :: syntax

let four = IpAddrKind::V4;
let six = IpAddrKind::V6;
enum IpAddrKind {
V4,
V6,
}

Why is it useful that the variants of the enum are
namespaced under its identifier?
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:

fn route(ip_kind: IpAddrKind) {
…
}
enum IpAddrKind {
V4,
V6,
}

struct IpAddr {
kind: IpAddrKind,
address: String,
}

let home = IpAddr {
kind: IpAddrKind::V4,
address: String::from("127.0.0.1"),
};

How do we represent the same concept using just an
enum?
Using just an enum is more concise: Rather than an
enum inside a struct, we can put data directly into
each enum variant
.

enum IpAddr {
V4(String),
V6(String),
}

let home = IpAddr::V4(String::from("127.0.0.1"));

This new definition says that both V4 and
V6 variants will have associated String
values.
enum IpAddr {
V4(u8, u8, u8, u8),
V6(String),
}

How do enums with data attached to them work under the
hood
?
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. We automatically get this constructor function
defined as a result of defining the enum.
enum IpAddrKind {
V4,
V6,
}

struct IpAddr {
kind: IpAddrKind,
address: String,
}

What could be a potential advantage to using an enum
here rather than a struct?
Let’s say if each variant had different types and amounts of
associated data
. Enums handle this case with ease:

enum IpAddr {
V4(u8, u8, u8, u8),
V6(String),
}

In this case: Version four type IP addresses will always have four
numeric components that will have values between 0 and
255. If we wanted to store V4 addresses as
four u8 values, but still express V6 addresses
as one String value, we wouldn’t be able to with a
struct.
enum Message {
Quit,
Move { x: i32, y: i32 },
Write(String),
ChangeColor(i32, i32, i32),
}

This enum has four variants with different types.
Explain the syntax used by Move and Quit
here.
Move has named fields like a struct does. Quit has no
data associated with it at all.
enum Message {
Quit,
Move { x: i32, y: i32 },
Write(String),
ChangeColor(i32, i32, i32),
}

How would you define these enum variants as structs?
struct QuitMessage; // Unit struct
struct MoveMessage {
x: i32,
y: i32,
};
struct WriteMessage(String); // Tuple struct
struct ChangeColorMessage(i32, i32, i32); // Tuple struct
enum Message {
Quit,
Move { x: i32, y: i32 },
Write(String),
ChangeColor(i32, i32, i32),
}

What else can we define on enums?
Methods

Just as we’re able to define methods on structs (using
impl), we’re also able to define methods on
enums.

impl Message {
fn call(&self) {
// …
}
}

let m = Message::Write(String::from("Hello"));
m.call();
I call it my billion-dollar mistake. At that time, I was designing
the first comprehensive type system for references in an object-oriented
language. My goal was to ensure that all use of references should be
absolutely safe, with checking performed automatically by the
compiler.

But I couldn’t resist the temptation to put in a null reference,
simply because it was so easy to implement. This has led to innumerable
errors, vulnerabilities, and system crashes, which have probably caused
a billion dollars of pain and damage in the last forty years.

Rust does not have nulls. What does it have instead?
The enum Option<T>. It’s an
enum that can encode the concept of a value being present
or absent. It is defined by the standard library as follows:

enum Option<T> {
None,
Some(T),
}

Note:

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.
let mut user1 = User {
email: String::from("someone@example.com"),
username: String::from("someusername123"),
active: true,
sign_in_count: 1,
}

How can we mark specific struct fields as mutable?
We can’t.

The entire instance must be mutable. Rust doesn’t allow us to mark
only certain fields as mutable.

Note:

An alternative workaround could be to use public getters with private
fields while having the rest of the fields be mutable.
What is match?
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.

Note:

The power of match comes from the expressiveness of the patterns and the
fact that the compiler confirms that all possible cases are handled.
enum Coin {
Penny,
Nickel,
Dime,
Quarter,
}

fn value_in_cents(coin: Coin) -> u8 {
##########
}

See if you can restore the blacked out code using
match.
First, we list the match keyword followed by an
expression.

Next are the match arms. An arm has two parts: A pattern
and some code, and the => operator that separates the
pattern and the code to run. Each arm is separated from the next with a
comma.

enum Coin {
Penny,
Nickel,
Dime,
Quarter,
}

fn value_in_cents(coin: Coin) -> u8 {
match coin {
Coin::Penny => 1,
Coin::Nickel => 5,
Coin::Dime => 10,
Coin::Quarter => 25,
}
}
When following an if, an expression needs to return a
Boolean value. What comes after we use the
match keyword?
An expression that can return any type.

enum Coin {
Penny,
Nickel,
Dime,
Quarter,
}

fn value_in_cents(coin: Coin) -> u8 {
match coin {
Coin::Penny => 1,
Coin::Nickel => 5,
Coin::Dime => 10,
Coin::Quarter => 25,
}
}

The type of coin in this example is the Coin enum
defined on the first line.
fn value_in_cents(coin: Coin) -> u8 {
match coin {
Coin::Penny => {
println!("Lucky penny!");
1
} // No comma here
Coin::Nickel => 5,
Coin::Dime => 10,
Coin::Quarter => 25,
}
}

Why is there no comma here?
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
. But we don’t typically use curly brackets if the
match arm code is short.
enum UsState {
Alabama,
Alaska,
// …
}

enum Coin {
Penny,
Nickel,
Dime,
Quarter(UsState),
}

How we can extract values out of enum variants
(UsState in this case)?
We add a variable (called state, in this case) to the
pattern that matches values of the variant
Coin::Quarter.

fn value_in_cents(coin: Coin) -> u8 {
match coin {
Coin::Penny => 1,
Coin::Nickel => 5,
Coin::Dime => 10,
Coin::Quarter(state) => {
println!("State quarter from {:?}!", state);
25
}
}
}

Then we can use state in the code for that arm.
let dice_roll = 9;

match dice_roll {
3 => add_fancy_hat(),
7 => remove_fancy_hat(),
other => move_player(other),
}

fn add_fancy_hat() { … }
fn remove_fancy_hat() { … }
fn move_player(num_spaces: u8) { … }

What happens here?
We take special actions for a few particular values, but for all
other values take one default action (using the so called catch-all
pattern).
What pattern can we use when we want a catch-all, but don’t want to
use the value in the catch-all pattern?
let dice_roll = 9;
match dice_roll {
3 => add_fancy_hat(),
7 => remove_fancy_hat(),
_ => reroll(),
}

fn add_fancy_hat() { … }
fn remove_fancy_hat() { … }
fn reroll() { … }

_ 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.
How can we have one arm of a match do
nothing
if its pattern matches?
By returning the unit value ().

let dice_roll = 9;

match dice_roll {
3 => add_fancy_hat(),
7 => remove_fancy_hat(),
_ => (),
}

fn add_fancy_hat() { … }
fn remove_fancy_hat() { … }

Here, we’re telling Rust explicitly that we aren’t going to use any
other value that doesn’t match a pattern in an earlier arm, and we don’t
want to run any code in this case.
let config_max = Some(3u8);

match config_max {
Some(max) => println!("The maximum is set to {}", max),
_ => (),
}

How can we shorten this annoying boilerplate?
Instead, we could write this in a shorter way using
if let:

let config_max = Some(3u8);

if let Some(max) = config_max {
println!("The maximum is set to {}", max);
}

The syntax if let takes a pattern and an expression
separated by an equal sign. It works the same way as a
match, where the expression is given to the
match and the pattern is its first arm.
What is the if let syntax?
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.

Note:

Choosing between match and if let depends on
whether gaining conciseness is an appropriate trade-off for losing the
exhaustive checking of match.
Can we include an else with an if let?
Yes.

let mut count = 0;

if let Coin::Quarter(state) = coin {
println!("State quarter from {:?}!", state);
}
else {
count += 1;
}
What are the 2 forms of a crate?
A binary crate or a library crate

Most of the time when Rustaceans say “crate”, they mean library
crate, and they use “crate” interchangeably with the general programming
concept of a “library”.
What’s a package?
A package is a bundle of one or more crates that provides a set of
functionality. It also contains a Cargo.toml file that
describes how to build those crates.
What can a package contain?
A package can contain as many binary crates as you like, but at most
only one library crate. Either way, a package must
contain at least one crate, whether that’s a library or binary
crate.
What is cargo’s convention for the crate root file of a binary crate
with the same name as the package?
src/main.rs
What is cargo’s convention for the crate root file of a library crate
with the same name as the package?
src/lib.rs
What does it mean if a package contains src/main.rs and
src/lib.rs?
It means that it has (at least) two crates: A binary and a library,
both with the same name as the package.
What’s the limit on the number of binary crates a package can
have?
A package can have multiple binary crates.

Note:

This can be done by placing files in the src/bin directory:
Each file will be a separate binary crate.
What’s the purpose of the use keyword?
To bring a path into scope
When compiling a crate, where does the compiler usually start
from?
It starts from the crate root.

When compiling a crate, the compiler first looks in the crate root
file (usually src/lib.rs for a library crate or
src/main.rs for a binary crate) for code to compile.
mod garden;

What’s the order of lookups (performed by the compiler) when
declaring a module, say, named garden in the root
crate?
Inline, within curly brackets that replace the ;
following mod garden

In the file src/garden.rs

In the file src/garden/mod.rs
In any file other than the crate root, you can declare
submodules.

For example, you might declare mod vegetables; in
src/garden.rs. In what order will the compiler look for the
submodule’s code?
Inline, directly following mod vegetables, within curly
brackets instead of the ;

In the file src/garden/vegetables.rs

In the file src/garden/vegetables/mod.rs
Code within a module is private from its parent modules by default.
How do you make a module public?
Declare it with pub mod instead of mod.
How do you make items within a public module public as well?
Use pub before their declarations.
What is the use keyword for?
Within a scope, the use keyword creates shortcuts to
items
to reduce repetition of long paths.

In any scope that can refer to
crate::gardens::vegetables::Asparagus you can create a
shortcut with use crate::gardens::vegetables::Asparagus;.
From then on you only need to write Asparagus to make use
of that type in the scope.
Why are the files src/main.rs and
src/lib.rs 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.

Filename: src/lib.rs

mod front_of_house {
mod hosting {
fn add_to_waitlist() { … }
fn seat_at_table() { … }
}
mod serving {
fn take_order() { … }
fn serve_order() { … }
fn take_payment() { … }
}
}

crate
\-- front_of_house
|-- hosting
| |-- add_to_waitlist
| \-- seat_at_table
\-- serving
|-- take_order
|-- serve_order
\-- take_payment
What are paths used for?
To show Rust where to find an item in a module tree, we use a path in
the same way we use a path when navigating a filesystem. To call a
function, we need to know its path.
What are the 2 forms of a path?
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.

Note:

Both absolute and relative paths are followed by one or more identifiers
separated by double colons (::).
When debating between relative and absolute paths, what is our likely
preference?
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.

Generally speaking, choosing whether to use a relative or absolute
path is a decision you’ll make based on your project, and depends on
whether you’re more likely to move item definition code separately from
or together with the code that uses the item.
What is the default access modifier / privacy rule for all items
(functions, methods, structs, enums, modules, and constants)?
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 simply put it in a
module.
What is the accessibility relationship between parent and child
modules?
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.

Explanation:

This is because child modules wrap and hide their implementation
details, but the child modules can see the context in which they’re
defined. To continue with our metaphor, think of the privacy rules as
being like the back office of a restaurant: What goes on in there is
private to restaurant customers, but office managers can see and do
everything in the restaurant they operate.
What do we have to do in order to hide inner implementation details
with modules?
Nothing.

Rust chose to have the module system function this way so that
hiding inner implementation details is the default.

That way, you know which parts of the inner code you can change
without breaking outer code.
How do we expose certain inner parts of child modules’ code?
Even though not by default, Rust does give you the option to expose
inner parts of child modules’ code to outer ancestor modules by
using the pub keyword to make an item public
.
mod front_of_house {
pub mod hosting {
fn add_to_waitlist() { … }
}
}

pub fn eat_at_restaurant() {
// Absolute path
crate::front_of_house::hosting::add_to_waitlist();

// Relative path
front_of_house::hosting::add_to_waitlist();
}

What’s going to happen here?
Compile-time error.

Explanation:

The pub keyword on a module only lets code in its
ancestor modules refer to it, but the contents of the module are still
private. Making the module public doesn’t make its contents
public.
(Because modules are containers, there’s not much we
can do by only making the module public.)
How do we 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.)

fn deliver_order() { … }

mod back_of_house {
fn fix_incorrect_order() {
cook_order();
super::deliver_order();
}

fn cook_order() { … }
}
fn deliver_order() { … }

mod back_of_house {
fn fix_incorrect_order() {
cook_order();
super::deliver_order();
}

fn cook_order() { … }
}

What is the meaning of super here?
It allows us to construct relative paths that begin in the
parent module
, rather than the current module or the crate
root. (Like starting a filesystem path with the ..
syntax.)
What’s the extra few details we want to be aware of around the usage
of pub with structs?
We use pub before a struct definition, we make the
struct public, but the struct’s fields will still be
private
. We can make each field public or not on a case-by-case
basis.

pub struct Breakfast {
pub toast: String,
seasonal_fruit: String,
}
mod back_of_house {
pub struct Breakfast {
pub toast: String,
seasonal_fruit: String,
}

impl Breakfast {
pub fn summer(toast: &str) -> Breakfast {
Breakfast {
toast: String::from(toast),
seasonal_fruit: String::from("peaches"),
}
}
}
}

If we didn’t have summer here, what could have been a
consequence?
Because of the private field, the struct needs to provide a
public associated function that constructs an instance of
Breakfast
(AKA summer).

If Breakfast didn’t have such a function, we couldn’t
create an instance of Breakfast in
eat_at_restaurant, because we couldn’t set the value of the
private seasonal_fruit field in
eat_at_restaurant.
mod back_of_house {
pub enum Appetizer {
Soup,
Salad,
}
}

What’s the default access modifier / privacy rule for
enum variants?
Public.

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.
What’s the default access modifier / privacy rule for struct
fields?
Private.

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.
mod front_of_house {
pub mod hosting {
pub fn add_to_waitlist() { … }
}
}

use crate::front_of_house::hosting;

How can we call add_to_waitlist?
Since we’ve brought the module into the scope, we only have to
specify hosting::add_to_waitlist to call the
function
.

mod front_of_house {
pub mod hosting {
pub fn add_to_waitlist() { … }
}
}

use crate::front_of_house::hosting;

pub fn eat_at_restaurant() {
hosting::add_to_waitlist();
}

Hosting is now a valid name in that scope, just as though the hosting
module had been defined in the crate root.
mod front_of_house {
pub mod hosting {
pub fn add_to_waitlist() { … }
}
}

use crate::front_of_house::hosting;

mod customer {
pub fn eat_at_restaurant() {
hosting::add_to_waitlist();
}
}

What happens here?
Compile-time error!

Note that use only creates the shortcut for the
particular scope in which the use occurs.

Since the child module named customer is a different scope than the
use statement, the function body won’t compile. The error will let it be
known that the shortcut does not apply within the customer module.
mod front_of_house {
pub mod hosting {
pub fn add_to_waitlist() { … }
}
}

use crate::front_of_house::hosting;

mod customer {
pub fn eat_at_restaurant() {
hosting::add_to_waitlist();
}
}

How can we fix the scope related compilation error induced here?
We can move the use within the customer module, or
reference the shortcut in the parent module with
super::hosting within the child customer module.
mod front_of_house {
pub mod hosting {
pub fn add_to_waitlist() { … }
}
}

use crate::front_of_house::hosting;

pub fn eat_at_restaurant() {
hosting::add_to_waitlist();
}

Why did we specify use hosting and then called
hosting::add_to_waitlist rather than specifying the use
path all the way out to the add_to_waitlist function to
achieve the same result?
This is the idiomatic way to bring a function into scope with
use.

The following code, on the other hand:

mod front_of_house {
pub mod hosting {
pub fn add_to_waitlist() { … }
}
}

use crate::front_of_house::hosting::add_to_waitlist;

pub fn eat_at_restaurant() {
add_to_waitlist();
}

… is unclear as to where add_to_waitlist is defined.

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.
use crate::front_of_house::hosting;

mod customer {
pub fn eat_at_restaurant() {
hosting::add_to_waitlist();
}
}

When do we diverge from this idiom of bringing the function’s
parent module into scope
(in order to have to specify the
parent module when calling the function)?
When bringing in structs, enums, and other items with
use, it’s instead idiomatic to specify the full path.

use std::collections::HashMap;

fn main() {
let mut map = HashMap::new();
map.insert(1, 2);
}

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.
use std::collections::HashMap;

fn main() {
let mut map = HashMap::new();
map.insert(1, 2);
}

What’s the exception to this idiom of specifying the full path when
bringing in structs, enums, and other items with use?
The exception to this idiom is if we’re bringing two items with the
same name into scope with use statements, because Rust
doesn’t allow that.

use std::fmt;
use std::io;

fn function1() -> fmt::Result { … }

fn function2() -> io::Result<()> { … }
use std::fmt;
use std::io;

fn function1() -> fmt::Result { … }

fn function2() -> io::Result<()> { … }

What’s an alternative solution to bringing two types of the same name
into the same scope?
By renaming one of the two Result types using as.

use std::fmt::Result;
use std::io::Result as IoResult;

fn functionl() -> Result { … }

fn function2() -> IoResult<()> { … }
use std::fmt;
use std::io;

fn function1() -> fmt::Result { … }

fn function2() -> io::Result<()> { … }

use std::fmt::Result;
use std::io::Result as IoResult;

fn functionl() -> Result { … }

fn function2() -> IoResult<()> { … }

Which of these 2 is considered an idiomatic way of importing two
types of the same name?
Both. The choice is up to you.
How can we re-export a name we brought into scope?
By combining pub and use.

mod front_of_house {
pub mod hosting {
pub fn add_to_waitlist() { … }
}
}

pub use crate::front_of_house::hosting;

pub fn eat_at_restaurant() {
hosting::add_to_waitlist();
}

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.
When is re-exporting names useful?
Re-exporting is useful when the internal structure of your code is
different from how programmers calling your code would think about the
domain.

For example, in a restaurant metaphor, the people running the
restaurant think about “front of house” and “back of house.” But
customers visiting a restaurant probably won’t think about the parts of
the restaurant in those terms. With pub use, we can write
our code with one structure, but expose a different structure
Is there anything specific we need to do when using the standard
library?
We do need to refer to it with use to
bring items from there into our package’s scope, since the standard
std library is also a crate that’s external to our
package.

On the other hand, we do not need to change Cargo.toml
to include std, since the standard library is shipped with
the Rust language.

use std::collections::HashMap;
// …
use std::cmp::Ordering;
use std::io;
// …

How can we shorten this?
With curly brackets:

// …
use std::{cmp::0rdering, io};
// …
use std::io;
use std::io::Write;

How can we shorten this?
By using self:

use std::io::{self, Write};

This line brings both std::io and
std::io::Write into scope.
How do we bring all public items defined in
std::collections into scope?
With the glob operator

use std::collections::
;

Warning:

Be careful when using the glob operator! Glob can drastically
reduce readability
by making it harder to tell what names are
in scope and where a name used in your program was defined.
use std::collections::*;

What is a common use for the glob operator?
When testing, to bring everything under test into
the tests module.
How often should we load a file using a mod
declaration?
Note that you only need to load a file using a mod
declaration once in your module tree.

mod front_of_house;

pub use crate::front_of_house::hosting;

pub fn eat_at_restaurant() {
hosting::add_to_waitlist();
}

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.

In other words, mod is not an “include” operation that
you may have seen in other programming languages.
For a module named front_of_house declared in the crate
root,

src/front_of_house.rs

src/front_of_house/mod.rs

Which of the paths above is idiomatic for the compiler to look
for?
1 is idiomatic, 2 is an older style but is still supported.

The main downside to the style that uses files named
mod.rs is that your project can end up with many files
named mod.rs, which can get confusing when you have them
open in your editor at the same time.
For a module named hosting that is a submodule of front_of_house,

src/front_of_house/hosting/mod.rs

src/front_of_house/hosting.rs

which of the paths above is idiomatic for the compiler to look
for?
2 is idiomatic, 1 is an older style but still supported.

The main downside to the style that uses files named
mod.rs is, that your project can end up with many files
named mod.rs, which can get confusing when you have them
open in your editor at the same time.
What’s the Vec<T> collection type?
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.
What’s an example use for vectors?
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.

+357 more cards