Systemnahe Programmierung mit Rust
https://rust-book.cs.brown.edu
Letzter Update: 2024-10-14
Getting Started
What is the name of the command-line tool for managing the version of Rust on your machine?
Every executable Rust program must contain a function with the name:
Let’s say you have the following program in a file hello.rs:
fn main() {
println!("Hello world!");
}
Say you then run the command rustc hello.rs from the command-line. Which statement best describes what happens next?
rustc will print an error because this is an invalid program
rustc reformats hello.rs according to the Rust style guide
rustc executes the program and prints out Hello world!
rustc generates a binary executable named hello
Say you just downloaded a Cargo project, and then you run cargo run at the command-line. Which statement is NOT true about what happens next?
A Guessing Game
No Quiz
Common Programming Concepts
Which statement best describes what it means if a variable x is immutable?
What is the keyword used after let to indicate that a variable can be mutated?
Determine whether the program will pass the compiler. If it passes, write the expected output of the program if it were executed.
fn main() {
let x = 1;
println!("{x}");
+= 1;
x println!("{x}");
}
This program:
( ) DOES compile. Output: __________
( ) does NOT compile
Which of the following statements is correct about the difference between using let and const to declare a variable?
const can be used in the global scope, and let can only be used in a function
They are just different syntaxes for declaring variables with the same semantics
A const can only be assigned to a literal, not an expression involving computation
The compiler will error if a const variable’s name is not using UPPER_SNAKE_CASE
Determine whether the program will pass the compiler. If it passes, write the expected output of the program if it were executed.
const TWO: u32 = 1 + 1;
fn main() {
println!("{TWO}");
}
This program:
( ) DOES compile
( ) does NOT compile
Determine whether the program will pass the compiler. If it passes, write the expected output of the program if it were executed.
fn main() {
let mut x: u32 = 1;
{
let mut x = x;
+= 2;
x }
println!("{x}");
}
This program:
( ) DOES compile. Output __________
( ) does NOT compile
Determine whether the program will pass the compiler. If it passes, write the expected output of the program if it were executed.
fn main() {
let mut x: u32 = 1;
= "Hello world";
x println!("{x}");
}
This program:
( ) DOES compile. Output __________
( ) does NOT compile
The largest number representable by the type i128
is:
2^128
2^128 - 1
2^127
2^127 - 1
if x : u8 = 0
, what will happen when computing
x - 1
?
Determine whether the program will pass the compiler. If it passes, write the expected output of the program if it were executed.
fn main() {
let x: fsize = 2.0;
println!("{x}");
}
This program:
( ) DOES compile: Output __________
( ) does NOT
compile
Determine whether the program will pass the compiler. If it passes, write the expected output of the program if it were executed.
fn main() {
let message = "The temperature today is:";
let x = [message, 100];
println!("{} {}", x[0], x[1]);
}
This program:
( ) DOES compile: Output __________
( ) does NOT
compile
Determine whether the program will pass the compiler. If it passes, write the expected output of the program if it were executed.
fn main() {
let t = ([1; 2], [3; 4]);
let (a, b) = t;
println!("{}", a[0] + t.1[0]);
}
This program:
( ) DOES compile: Output __________
( ) does NOT compile
The keyword for declaring a new function in Rust is:
Your input: ____
Determine whether the program will pass the compiler. If it passes, write the expected output of the program if it were executed.
fn f(x) {
println!("{x}");
}
fn main() {
0);
f(}
This program:
( ) DOES compile: Output __________
( ) does NOT compile
In Rust, a curly-brace block like { ... }
is:
1 An expression 2 A statement 3 A syntactic scope
Determine whether the program will pass the compiler. If it passes, write the expected output of the program if it were executed.
fn f(x: i32) -> i32 {
+ 1
x }
fn main() {
println!(
"{}",
{
f(let y = 1;
+ 1
y })
;
)}
This program:
( ) DOES compile: Output __________
( ) does NOT compile
True/false: executing these two pieces of code results in the same value for x.
Snippet 1:
let x = if cond { 1 } else { 2 };
Snippet 2:
let x;
if cond {
= 1;
x } else {
= 2;
x }
(Note: both of these snippets compile!)
Determine whether the program will pass the compiler. If it passes, write the expected output of the program if it were executed.
fn main() {
let x = 1;
let y = if x { 0 } else { 1 };
println!("{y}");
}
This program:
( ) DOES compile: Output __________
( ) does NOT compile
True/false: this code will terminate (that is, it will not loop forever).
fn main() {
let mut x = 0;
'a: loop {
+= 1;
x 'b: loop {
if x > 10 {
continue 'a;
} else {
break 'b;
}
}
break;
}
}
Determine whether the program will pass the compiler. If it passes, write the expected output of the program if it were executed.
fn main() {
let a = [5; 10];
let mut sum = 0;
for x in a {
+= x;
sum }
println!("{sum}");
}
This program:
( ) DOES compile: Output __________
( ) does NOT compile
Understanding Ownership
4.1
Which of the following is NOT a kind of undefined behavior?
Determine whether the program will pass the compiler. If it passes, write the expected output of the program if it were executed.
fn add_suffix(mut s: String) -> String { s.push_str(” world”); s }
fn main() { let s = String::from(“hello”); let s2 = add_suffix(s); println!(“{}”, s2); }
This program: () DOES compile. Output: ****__****
() does NOT compile
Determine whether the program will pass the compiler. If it passes, write the expected output of the program if it were executed.
fn main() { let s = String::from(“hello”); let s2; let b = false; if b { s2 = s; } println!(“{}”, s); }
This program: () DOES compile. Output: ******_******
() does NOT compile
Say we have a function that moves a box, like this:
fn move_a_box(b: Box
Below are four snippets which are rejected by the Rust compiler. Imagine that Rust instead allowed these snippets to compile and run. Select each snippet that would cause undefined behavior, or select “None of the above” if none of these snippets would cause undefined behavior.
None of the above
let b = Box::new(0); move_a_box(b); println!(“{}”, b);
let b = Box::new(0); let b2 = b; println!(“{}”, b); move_a_box(b2);
let b = Box::new(0); let b2 = b; move_a_box(b);
let b = Box::new(0); move_a_box(b); let b2 = b;
4.2 References and Borrowing
Consider the following program, showing the state of memory after the last line:
let x = Box::new(0); let y = Box::new(&x);L1
If you wanted to copy out the number 0 through y, how many dereferences would you need to use? Write your answer as a digit. For example, if the correct expression is *y, then the answer is 1.
Consider the following program, showing the state of memory after the last line:
fn get_first(vr: &Vec
fn main() { let mut v = vec![0, 1, 2]; let n = get_first(&v); println!(“{} {}”, n, v[1]);L1 }
Which of the following best explains why v is not deallocated after calling get_first?
Consider the permissions in the following program:
let mut s = String::from(“Hello”);
let t = &mut s;
/_ here _/ t.push_str(” world”);
println!(“{}”, s);
At the point marked /_ here _/, what are the permissions on the path s? Select each permission below, or select “no permissions” if the path has no permissions.
Consider the permissions in the following program:
Which of the following best explains why strs loses and regains write permissions?
get_first returns an immutable reference to data within strs, so strs is not writable while first is live
strs is not writable while the immutable reference &strs passed to get_first is live
strs does not need write permissions until the strs.push(..) operation, so it only regains write permissions at that statement
Because first refers to strs, then strs can only be mutated within a nested scope like the if-statement
Consider this unsafe program:
let v1 = vec![1, 2, 3]; let mut v2 = v1; v2.push(4); println!(“{}”, v1[0]);L1
Which of the following best describes the point at which undefined behavior occurs in this program?
Response
v1 has been moved into v2 on line 2
v1[0] reads v1, which points to deallocated memory
v1 has its pointer invalidated by the push on line 3
v2 owns the vector data on the heap, while v1 does not
Determine whether the program will pass the compiler. If it passes, write the expected output of the program if it were executed.
fn incr(n: &mut i32) { *n += 1; } fn main() { let mut n = 1; incr(&n); println!(“{n}”); }
This program:
() DOES compile. Output: ****__****
() does NOT compile
Determine whether the program will pass the compiler. If it passes, write the expected output of the program if it were executed.
fn main() { let mut s = String::from(“hello”); let s2 = &s; let s3 = &mut s; s3.push_str(” world”); println!(“{s2}”); }  This program:  DOES compile OR does NOT compile
Consider this Rust function that pushes a number onto the end of a vector, and then removes and returns the number from the front of the vector:
fn give_and_take(v: &Vec
Normally, if you try to compile this function, the compiler returns the following error:
error[E0596]: cannot borrow *v
as mutable, as it is
behind a &
reference –> test.rs:2:5 | 1 | fn
give_and_take(v: &Vec&mut Vec<i32>
2 | v.push(n); | ^^^^^^^^^
v
is a &
reference, so the data it refers
to cannot be borrowed as mutable
Assume that the compiler did NOT reject this function. Select each (if any) of the following programs that could possibly cause undefined behavior if executed. If none of these programs could cause undefined behavior, then check “None of these programs” .

 let v = vec![1, 2, 3]; let n = &v[0]; give_and_take(&v, 4); println!(“{}”, n); 
None of these programs
- let v = vec![1, 2, 3]; let v2 = &v; give_and_take(&v, 4); println!(“{}”, v2[0]); 
let v = vec![1, 2, 3]; let n = &v[0]; let k = give_and_take(&v, 4); println!(“{}”, k);
4.3 Fixing Ownership Errors
Which of the following is NOT a valid kind of fix to the issue of returning a stack reference from a function?
Let’s say a programmer tried writing the following function:
/// Returns a person’s name with “Ph.D.” added as a title fn award_phd(name: &String) -> String { let mut name = *name; name.push_str(“, Ph.D.”); name }
The Rust compiler rejects their code with the following error:
error[E0507]: cannot move out of *name
which is behind a
shared reference –> test.rs:3:20 | 3 | let mut name = *name; | ^^^^^
| | | move occurs because *name
has typeString
,
which does not implement the Copy
trait | help: consider
borrowing here:&*name
Given the stated purpose of the function, which of the following would be the most idiomatic fix to the program? The differences from the function above are highlighted.
Response  - fn award_phd(name: &String) -> String { let mut name = &*name; name.push_str(“, Ph.D.”); name } 
fn award_phd(name: &String) -> String { let mut name = name.clone(); name.push_str(“, Ph.D.”); name } 
fn award_phd(name: &mut String) { name.push_str(“, Ph.D.”); } 
fn award_phd(mut name: String) -> String { name.push_str(“, Ph.D.”); name }
Let’s say a programmer tried writing the following function:
/// Rounds all the floats in a vector to the nearest integer,
in-place fn round_in_place(v: &Vec
The Rust compiler rejects their code with the following error:
error[E0594]: cannot assign to *n
, which is behind a
&
reference –> test.rs:4:9 | 3 | for n in v { | -
this iterator yields &
references 4 | *n = n.round(); |
^^^^^^^^^^^^^^ n
is a &
reference, so the
data it refers to cannot be written
Given the stated purpose of the function, which of the following would be the most idiomatic fix to the program? The differences from the function above are highlighted.
Response  - fn round_in_place(v: &Vec
fn round_in_place(mut v: Vec
} 
fn round_in_place(v: &Vec
} 
fn round_in_place(v: &mut Vec
Which of the following best explains why an i32 can be copied without a move, but a String cannot?

The following code snippet does not compile:
let s = String::from(“Hello world”); let s_ref = &s; let s2 = *s_ref; println!(“{s2}”);
Which of the following best describes the undefined behavior that could occur if this program were allowed to execute?
Response
The following program does not compile:
fn copy_to_prev(v: &mut Vec
fn main() { let mut v = vec![1, 2, 3]; copy_to_prev(&mut v, 1); }
Which of the following best describes the undefined behavior that could occur if this program were allowed to execute?
Response  
Consider this function that is a simplified variant of the function from the previous quiz:
/// Adds “Ph.D.” to a person’s name fn award_phd(name: &String) { let mut name = *name; name.push_str(“, Ph.D.”); }
The Rust compiler rejects this function with the following error:
error[E0507]: cannot move out of *name
which is behind a
shared reference –> test.rs:3:20 | 3 | let mut name = *name; | ^^^^^
| | | move occurs because *name
has typeString
,
which does not implement the Copy
trait | help: consider
borrowing here:&*name
Assume that the compiler did NOT reject this function. Select each (if any) of the following programs that could possibly cause undefined behavior if executed. If none of these programs could cause undefined behavior, then check “None of these programs” .
Response  - let name = String::from(“Ferris”); let name_ref = &name; award_phd(&name); println!(“{}”, name_ref); 
None of these programs
- let name = String::from(“Ferris”); award_phd(&name); 
let name = String::from(“Ferris”); award_phd(&name); println!(“{}”, name);
Determine whether the program will pass the compiler. If it passes, write the expected output of the program if it were executed.
fn main() { let mut point = [0, 1]; let mut x = point[0]; let y = &mut point[1]; x += 1; *y += 1; println!(“{} {}”, point[0], point[1]); }  This program:  DOES compile OR does NOT compile
4.4 The Slice Type
Consider the variables s2 and s3 in the following program. These two variables will be located in memory within the stack frame for main. Each variable has a size in memory on the stack, not including the size of pointed data. Which statement is true about the sizes of s2 and s3?
fn main() { let s = String::from(“hello”); let s2: &String = &s; let s3: &str = &s[..]; }  
Determine whether the program will pass the compiler. If it passes, write the expected output of the program if it were executed.
fn main() { let mut s = String::from(“hello”); for &item in s.as_bytes().iter() { if item == b’l’ { s.push_str(” world”); } } println!(“{s}”); }  This program:  DOES compile OR does NOT compile
4.5 Ownership Recap
Say you are writing a function with the following spec:
round_all takes as input a list of floating point numbers, and it rounds each number in-place to the nearest integer.
Which of the following is the most appropriate type signature for a function implementing this spec?

Say you are writing a function with the following spec:
find_contains takes as input a collection of strings and a target substring. It returns a list of all the strings in the collection that contain the target substring.
Which of the following is the most appropriate type signature for a function implementing this spec?

Rust normally disallows multiple mutable accesses to the same array, even when those accesses are disjoint. For example, this function does not compile:
fn main() { let mut v = vec![0, 1, 2, 3]; let (r0, r1) = (&mut
v[0..2], &mut v[2..4]); r0[0] += 1; r1[0] += 1;
}
However, the Rust standard library has a function slice::split_at_mut that does permit this functionality:
fn main() { let mut v = vec![0, 1, 2, 3]; let (r0, r1) =
v.split_at_mut(2); r0[0] += 1; r1[0] += 1;
}
Which of the following best describes how it’s possible to implement split_at_mut?
Consider the permissions in the following program:
❓ let s = String::new();» let s_ref = &

Ownership permits reading, and reading *s_ref can cause a use-after-free 
Ownership permits moving, and moving out of a reference can cause a double-free
Ownership permits borrowing, and reborrowing *s_ref can cause a double-free 
Ownership permits mutation, and mutating *s_ref can cause a use-after-free
Consider the set of Rust programs that contain no unsafe code. Select each of the following statements that is true about the kinds of programs accepted and rejected by the borrow checker:

The borrow checker always accepts programs without undefined behavior 
The borrow checker sometimes accepts programs with undefined behavior
The borrow checker sometimes rejects programs without undefined behavior
The borrow checker always rejects programs with undefined behavior
fn extract(b: &Box
Imagine that the borrow checker did not reject this function. Determine whether there exists an input such that the function would cause undefined behavior if executed on that input.

The function transfer_string is rejected by the borrow checker:
fn get_first(strs: &mut (String, String)) -> &mut String { &mut strs.0 }
fn get_second(strs: &mut (String, String)) -> &mut String { &mut strs.1 }
fn transfer_string(strs: &mut (String, String)) { let fst = get_first(strs); let snd = get_second(strs); fst.push_str(snd); snd.clear(); }
Imagine that the borrow checker did not reject this function. Determine whether there exists an input such that the function would cause undefined behavior if executed on that input.
Response 
This function could NOT cause undefined behavior
This function COULD cause undefined behavior
Using Structs
5.1
Determine whether the program will pass the compiler. If it passes, write the expected output of the program if it were executed.
struct Point { x: i32, y: i32, }
fn main() { let mut a = Point { x: 1, y: 2 }; a.x += 1; let b = Point { y: 1, ..a }; a.x += 1; println!(“{}”, b.x); }  This program:  DOES compile OR does NOT compile
Determine whether the program will pass the compiler. If it passes, write the expected output of the program if it were executed.
struct Point { x: i32, y: i32, } fn main() { let mut p = Point { x: 1, y: 2 }; let x = &mut p.x; let y = &mut p.y; x += 1; y += 1; println!(“{} {}”, p.x, p.y); }  This program:  DOES compileOR does NOT compile
5.2
Determine whether the program will pass the compiler. If it passes, write the expected output of the program if it were executed.
#[derive(Debug)] struct Rectangle { width: u32, height: u32, }
fn main() { let rect1 = Rectangle { width: 30, height: 50, }; let a = area(rect1); println!(“{} * {} = {}”, rect1.width, rect1.height, a); }
fn area(rectangle: Rectangle) -> u32 { rectangle.width * rectangle.height }  This program:  DOES compile OR does NOT compile
Which statement best describes a difference between the Display and Debug traits?
There is no difference, Display and Debug are aliases for the same trait. 
Display is for presenting values to an end-user, while Debug is for developers’ internal use
Display is for printing values to the console, while Debug is for viewing values in a debugger 
Display cannot be implemented for structs, while Debug can be implemented for structs
5.3
What is the keyword for constructor functions in Rust?
struct Point(i32, i32); fn main() { let p = Point(1, 2); impl p { fn x(&self) -> i32 { self.0 } }
println!(“{}”, p.x()); }  This program:  DOES compile OR does NOT compile
Say you have a variable v of type &mut Vec
impl Vec
If you try to compile the expression v.len(), which of the following statements best describes what happens?
It compiles, because &self can take any kind of reference 
It compiles, because the &mut reference is implicitly reborrowed as an & reference 
It does not compile, v is not explicitly dereferenced
It does not compile, because &mut Vec
Consider these two methods that increment a field of a struct. Which style would be more idiomatic for Rust?
struct Point(i32, i32); impl Point { fn incr_v1(mut self) { self.0 += 1; } fn incr_v2(&mut self) { self.0 += 1; } }  
Determine whether the program will pass the compiler. If it passes, write the expected output of the program if it were executed.
struct Point(i32, i32);
impl Point { fn incr_x(&mut self) { self.0 += 1; } }
fn main() { let mut p = Point(0, 0); p.incr_x(); println!(“{}”, p.0); }  This program:  DOES compile OR does NOT compile
Determine whether the program will pass the compiler. If it passes, write the expected output of the program if it were executed.
struct Point { x: i32, y: i32 }
impl Point { fn get_x(&mut self) -> &mut i32 { &mut self.x } }
fn main() { let mut p = Point { x: 1, y: 2 }; let x = p.get_x(); x += 1; println!(“{} {}”, x, p.y); }  This program:  DOES compile OR does NOT compile
Enums and Pattern Matching
6.1
Determine whether the program will pass the compiler. If it passes, write the expected output of the program if it were executed.
fn foo(x: &i32) { println!(“{x}”); }
fn main() { let x = null; foo(x); }  This program:  DOES compile OR does NOT compile
Consider these two representations of a Result type that contains a value T if a computation succeeds, or an error E if it fails.
struct Result1<T, E> { ok: Option
enum Result2<T, E> { Ok(T), Err(E) }
The enum Result2 is considered more idiomatic than the struct Result1 in Rust. Which statement below is NOT a valid reason why?

6.2
Determine whether the program will pass the compiler. If it passes, write the expected output of the program if it were executed.
enum Location { Point(i32), Range(i32, i32) }
fn main() { let l: Location = Location::Range(0, 5); let n = match l { Location::Point() => -1, Location::Range(, n) => n, Location::Range(0, ) => 0, => -2 }; println!(“{n}”); }  This program:  DOES compile OR does NOT compile
Consider this method implemented for the Option type:
impl
Which sentence best describes the behavior of this function?

Determine whether the program will pass the compiler. If it passes, write the expected output of the program if it were executed.
#[derive(Debug)] enum Either { Left(usize), Right(String) }
fn main() { let x = Either::Right(String::from(“Hello world”)); let value = match x { Either::Left(n) => n, Either::Right(s) => s.len() }; println!(“{x:?} {value}”); }  This program:  DOES compile OR does NOT compile
Consider these two implementations of a function to decrement an unsigned number twice.
fn decr_twice_v1(n: u32) -> Option
fn decr_twice_v2(n: u32) -> Option
The functions have the same behavior for:  
6.3
Which control flow construct would be most idiomatic to use in the following function?
enum Location { Point(i32), Range(i32, i32) }
fn print_range_max(loc: &Location) {
// print the second field of Range, if loc is a Range }
Response 
Which control flow construct would be most idiomatic to use in the following function?
enum Location { Point(i32), Range(i32, i32) }
fn get_start(loc: &Location) -> i32 { // return the first
field of Range or the only field of Point
}
Response  
6.4
Ownership Inventory #1 (uses “in-browser IDE”) – geht bei mir nur in Firefox!
A few important caveats about this experimental technology:
PLATFORM COMPATIBILITY: the in-browser IDE does not work on touch-screens. The in-browser IDE has only been tested to work on Google Chrome 109 and Firefox 107. It definitely does not work in Safari.
MEMORY USAGE: the in-browser IDE uses a WebAssembly build of rust-analyzer, which can take up a fair amount of memory. Each instance of the IDE appears to take around ~300 MB. (Note: we have also received some reports of >10GB memory usage.)
SCROLLING: the in-browser IDE will “eat” your cursor if your cursor intersects with the editor while scrolling. If you’re having trouble scrolling the page, try moving your cursor onto the rightmost scrollbar.
LOAD TIMES: the IDE may take up to 15 seconds to initialize for a new program. It will say “Loading…” as you interact with code in the editor.
Program:
/// Makes a string to separate lines of text, /// returning a default if the provided string is blank fn make_separator(user_str: &str) -> &str { if user_str == “” { let default = “=”.repeat(10); &default } else { user_str } }
If you tried to compile this function, which of the following best describes the compiler error you would get?

Program:
/// Makes a string to separate lines of text, /// returning a default if the provided string is blank fn make_separator(user_str: &str) -> &str { if user_str == “” { let default = “=”.repeat(10); &default } else { user_str } }
Normally if you try to compile this function, the compiler returns the following error:
error[E0515]: cannot return reference to local variable
default
–> test.rs:6:9 | 6 | &default | ^^^^^^^^
returns a reference to data owned by the current function Assume that
the compiler did NOT reject this function. Which (if any) of the
following programs would (1) pass the compiler, and (2) possibly cause
undefined behavior if executed? Check each program that satisfies both
criteria, OR check “None of these programs” if none are satisfying.
Response 
Program
/// Makes a string to separate lines of text, /// returning a default if the provided string is blank fn make_separator(user_str: &str) -> &str { if user_str == “” { let default = “=”.repeat(10); &default } else { user_str } }
Of the following fixes (highlighted in yellow), which fix best satisfies these three criteria:
The fixed function passes the Rust compiler,
The fixed function preserves the intention of the original code, and
The fixed function does not introduce unnecessary inefficiencies
fn make_separator(user_str: &str) -> String { if user_str
== “” { let default = “=”.repeat(10); default } else {
user_str.to_string()
} }
fn make_separator(user_str: &str) -> &str { if user_str == “” { let default = “=”.repeat(10); &default } else { &user_str } }
fn make_separator(user_str: String) -> String { if user_str == “” { let default = “=”.repeat(10); default } else { user_str } }
/// Gets the string out of an option if it exists, /// returning a
default otherwise fn get_or_default(arg: &Option
If you tried to compile this function, which of the following best describes the compiler error you would get?
Response 
arg does not live long enough
cannot move out of arg in arg.unwrap() 
cannot return s.clone() which does not live long enough 
cannot call arg.is_none() without dereferencing arg
/// Gets the string out of an option if it exists, /// returning a
default otherwise fn get_or_default(arg: &Option
Normally if you try to compile this function, the compiler returns the following error:
error[E0507]: cannot move out of *arg
which is behind a
shared reference –> test.rs:7:13 | 7 | let s = arg.unwrap(); |
^^^^——– | | | | | *arg
moved due to this method call |
help: consider calling .as_ref()
or .as_mut()
to borrow the type’s contents | move occurs because *arg
has type Option<String>
, which does not implement the
Copy
trait
Assume that the compiler did NOT reject this function. Which (if any) of the following programs would (1) pass the compiler, and (2) possibly cause undefined behavior if executed? Check each program that satisfies both criteria, OR check “None of these programs” if none are satisfying.
let opt = Some(String::from(“Rust”)); get_or_default(&opt); 
let opt = Some(String::from(“Rust”)); get_or_default(&opt); println!(“{:?}”, opt); 
None of these programs
let opt = Some(String::from(“Rust”)); let s = get_or_default(&opt); println!(“{}”, s);
/// Gets the string out of an option if it exists, /// returning a
default otherwise fn get_or_default(arg: &Option
Of the following fixes (highlighted in yellow), which fix best satisfies these three criteria:
The fixed function passes the Rust compiler,
The fixed function preserves the intention of the original code, and
The fixed function does not introduce unnecessary inefficiencies
fn get_or_default(arg: &mut Option
fn get_or_default(arg: &Option
fn get_or_default(arg: &Option<&str>) -> String { if arg.is_none() { return String::new(); } let s = arg.unwrap(); s.to_string() }
fn get_or_default(arg: Option
Packages, Crates and Modules
7.1
Which is the correct order, where “A > B” means “A contains B”?
Response  
Imagine you see a Rust package foobar with the following files:
foobar ├── Cargo.toml ├── build.rs └── src/ ├── main.rs ├── util.rs ├── lib.rs └── bin/ └── alt.rs
How many crates does this package contain? Write your answer as a digit, e.g. 0, 1, and so on.
Response
Answer: ****_****
7.2
Which of the following is NOT a benefit of using modules?
Response  
7.3
What is the keyword you use at the start of an absolute path to an item in the current crate?

Determine whether the program will pass the compiler. If it passes, write the expected output of the program if it were executed.
pub mod foo { fn a() { println!(“a”); } mod bar { pub fn b() { println!(“b”); } } } fn main() { foo::bar::b(); }
This program:  DOES compile OR does NOT compile
Determine whether the program will pass the compiler. If it passes, write the expected output of the program if it were executed.
pub mod foo { pub mod bar { pub fn b() { println!(“b”); } } pub fn a() { bar::b(); } } fn main() { foo::a(); }
This program:  DOES compile OR does NOT compile
Determine whether the program will pass the compiler. If it passes, write the expected output of the program if it were executed.
pub mod a { pub mod b { pub fn f() { println!(“b1”); } pub mod c { pub fn f() { println!(“c1”); } } } pub fn entry() { super:🅱️:c::f(); } }
pub mod b { pub fn f() { println!(“b2”); } pub mod c { pub fn f() { println!(“c2”); } } }
fn main() { crate:🅰️:entry(); }
Response  This program:  DOES compile OR does NOT compile
Determine whether the program will pass the compiler. If it passes, write the expected output of the program if it were executed.
pub mod point { #[derive(Debug)] pub struct Point(i32, i32); impl Point { pub fn origin() -> Self { Point(0, 0) } } }
fn main() { let mut p = point::Point::origin(); p.0 += 1; println!(“{p:?}”); }
Response  This program:  DOES compile OR does NOT compile
7.4
Which of the following statements best describes the function of the use keyword?
Consider this module and use statement:
pub mod parent { pub fn a() {} fn b() {} pub mod child { pub fn c() {} } }
fn main() { use parent::{*, child as alias}; // … }
Inside main, what is the total number of paths that can refer to a, b, or c (not including those that use self, super, or crate)? Write your answer as a digit such as 0 or 1. For example, if the only two valid paths were a and parent::b, then the answer would be 2.
Answer: **_**
7.5
Imagine a Rust package with the following directory structure:
foobar ├── Cargo.toml └── src/ ├── lib.rs ├── engine.rs └── engine/ └── analysis.rs
The contents of each file are:
// engine/analysis.rs pub fn run() {}
// engine.rs mod analysis; pub use analysis::*;
// lib.rs pub mod engine;
Say that another Rust developer is using the foobar library crate in a separate package, and they want to call the run function. What is the path they would write?
Common Collections
8.1
Which call to this find_until function will cause a runtime panic?
fn find_until(v: &Vec
Response 
Determine whether the program will pass the compiler. If it passes, write the expected output of the program if it were executed.
fn main() { let mut v = Vec::new(); let s = String::from(“Hello”); v.push(s); v[0].push_str(“world”); println!(“original: {}”, s); println!(“new: {}”, v[0]); }
Response  This program:  DOES compile OR does NOT compile
Determine whether the program will pass the compiler. If it passes, write the expected output of the program if it were executed.
fn main() { let v = vec![String::from(“Hello”)]; let mut s = v[0]; s.push_str(“world”); println!(“{s}”); }
Response  This program:  DOES compile OR does NOT compile
Determine whether the program will pass the compiler. If it passes, write the expected output of the program if it were executed.
fn main() { let mut v = vec![1, 2, 3]; for i in &mut v { v.push(*i); } println!(“{} {} {}”, v[3], v[4], v[5]); }
Response  This program:  DOES compile OR does NOT compile
Determine whether the program will pass the compiler. If it passes, write the expected output of the program if it were executed.
fn main() { let mut v: Vec
Response  This program:  DOES compile OR does NOT compile
8.2
What is the difference between using a + b and a.push_str(b) to concatenate two strings?
Response 
There is no difference, they are aliases for the same function 
push_str is more efficient at runtime than +
push_str consumes ownership of b, while + does not
What is the maximum number of times a heap allocation could occur in this program? Write your answer in digits, e.g. 0 or 1.
let s1 = String::from(“tic”); let s2 = String::from(“tac”); let s3 = String::from(“toe”); let s = s1 + “-” + &s2 + “-” + &s3;  Answer: ____
Which statement is the best explanation for why Rust does not allow string indexing?
Response  
Which statement best describes the difference between the types of a string slice &str and a byte slice &[u8]?
Response  
8.3
Determine whether the program will pass the compiler. If it passes, write the expected output of the program if it were executed.
use std::collections::HashMap; fn main() { let mut h = HashMap::new(); h.insert(“k1”, 0); let v1 = &h[“k1”]; h.insert(“k2”, 1); let v2 = &h[“k2”]; println!(“{} {}”, v1, v2); }
Response  This program:  DOES compile OR does NOT compile
Determine whether the program will pass the compiler. If it passes, write the expected output of the program if it were executed.
use std::collections::HashMap; fn main() { let mut h:
HashMap<char, Vec
Response  This program:  DOES compile OR does NOT compile
8.4 Ownership Inventory #2 (inspired by common stackoverflow questions)
/// Removes all the zeros in-place from a vector of integers. fn
remove_zeros(v: &mut Vec
If you tried to compile this function, which of the following best describes the compiler error you would get?
Response 
/// Removes all the zeros in-place from a vector of integers. fn
remove_zeros(v: &mut Vec
Normally if you try to compile this function, the compiler returns the following error:
error[E0502]: cannot borrow *v
as mutable because it is
also borrowed as immutable –> test.rs:5:13 | 3 | for (i, t) in
v.iter().enumerate().rev() { | ————————– | | | immutable borrow occurs
here | immutable borrow later used here 4 | if *t == 0 { 5 |
v.remove(i); | ^^^^^^^^^^^ mutable borrow occurs here
Assume that the compiler did NOT reject this function. Which (if any) of the following programs would (1) pass the compiler, and (2) possibly cause undefined behavior if executed? Check each program that satisfies both criteria, OR check “None of these programs” if none are satisfying.
let mut v = vec![5, 5, 0]; remove_zeros(&mut v); println!(“{:?}”, v);
let mut v = vec![1, 2, 0, 3]; remove_zeros(&mut v); 
None of these programs
let mut v = vec![1; 100]; remove_zeros(&mut v);
/// Removes all the zeros in-place from a vector of integers. fn
remove_zeros(v: &mut Vec
Of the following fixes (highlighted in yellow), which fix best satisfies these three criteria:
fn remove_zeros(v: Vec
fn remove_zeros(v: &mut Vec
fn remove_zeros(v: &mut Vec
fn remove_zeros(v: &Vec
// Reverses the elements of a vector in-place fn reverse(v: &mut
Vec
If you tried to compile this program, which of the following best describes the compiler error you would get?
Response  
cannot borrow v as mutable twice for v[i] and v[n - i - 1]
cannot borrow v as immutable for v.len() when v is a mutable borrow 
cannot mutably borrow an element v[i] of a mutable vector
/// Reverses the elements of a vector in-place fn reverse(v: &mut
Vec
Normally if you try to compile this function, the compiler returns the following error:
error[E0499]: cannot borrow *v
as mutable more than once
at a time –> test.rs:5:40 | 5 | std::mem::swap(&mut v[i],
&mut v[n - i - 1]); | ————– - ^ second mutable borrow occurs here |
| | | | first mutable borrow occurs here | first borrow later used by
call
Assume that the compiler did NOT reject this function. Which (if any) of the following programs would (1) pass the compiler, and (2) possibly cause undefined behavior if executed? Check each program that satisfies both criteria, OR check “None of these programs” if none are satisfying.
let mut v = vec![String::from(“a”), String::from(“b”)]; reverse(&mut v); println!(“{:?}”, v); 
None of these programs 
let mut v = vec![String::from(“a”), String::from(“b”)]; let x = &v[0]; reverse(&mut v); println!(“{x}”); 
let mut v = vec![String::from(“a”), String::from(“b”)]; reverse(&mut v);
// Reverses the elements of a vector in-place fn reverse(v: &mut
Vec
Of the following fixes (highlighted in yellow), which fix best satisfies these three criteria:
fn reverse(v: &mut Vec
fn reverse(v: &mut Vec
fn reverse(v: &mut Vec
for i in 0 .. n / 2 { let s1 = v[i].clone(); let s2 = v[n - i -
1].clone(); v[i] = s2; v[n - i - 1] = s1; } }
fn reverse(v: &Vec
for _ in 0 .. n { v2.push(v.pop().unwrap()); } v2 }
Error Handling
9.1
What is the name of the environment variable you should set to 1 to see the backtrace of a panic?
Answer: ____
Which of the following is NOT a good reason to use a panic?
9.2
Which of these statements best describes why File::open returns a Result and not an Option?
Because Result can represent why an operation failed, and file opening can fail for many reasons
Because Result represents the possibility of failure, while Option cannot represent failures
Because Result represents errors the same way as the underlying system calls
Because Result uses fewer bytes at runtime than Option to represent failures
Given an arbitrary expression e of type Result<T, E>, which code snippet best represents how e? is translated?Given an arbitrary expression e of type Result<T, E>, which code snippet best represents how e? is translated?

Determine whether the program will pass the compiler. If it passes, write the expected output of the program if it were executed.
// assume hello.txt has the contents “will” fn
read_username_from_file() -> Option
fn main() { println!(“{}”, read_username_from_file().unwrap()); }
 This program:  DOES compile OR does NOT compile
9.3
A Rust programmer is designing a library for writing command-line interfaces. As a part of this library, they are implementing a function to parse command-line flags provided by a user. Which implementation would be most appropriate for this domain?
fn parse_flag_v1(flag: &str) -> Result<String, String> { match flag.strip_prefix(“–”) { Some(no_dash) => Ok(no_dash.to_string()), None => Err(format!(“Invalid flag {flag}”)) } }
fn parse_flag_v2(flag: &str) -> String { match flag.strip_prefix(“–”) { Some(no_dash) => no_dash.to_string(), None => panic!(“Invalid flag {flag}”) } }
Response 
Generic Types, Traits and Lifetimes
10.1
Imagine using a third-party function whose implementation you don’t know, but whose type signature is this:
fn mystery
Then you call mystery like this:
let y = mystery(3);
Assuming mystery uses no unsafe code, then the value of y must be:
Answer: ****__****
Determine whether the program will pass the compiler. If it passes, write the expected output of the program if it were executed.
fn print_slice
fn main() { print_slice(&[1, 2, 3]); }
Response  This program: DOES compile OR does NOT compile
Output: ?
Hinweis:
fn print_slice<T: std::fmt::Display>(v: &[T]) {
Determine whether the program will pass the compiler. If it passes, write the expected output of the program if it were executed.
struct Point
impl
fn main() { let p: Point
10.2
Determine whether the program will pass the compiler. If it passes, write the expected output of the program if it were executed.
trait MakeNoise { fn make_noise(&self) { println!(“(silence)”); } }
struct Dog {}
struct Cat {}
impl MakeNoise for Dog { fn make_noise(&self) { println!(“bark”); } }
impl MakeNoise for Cat {}
fn main() { let dog = Dog {}; let cat = Cat {}; dog.make_noise(); cat.make_noise(); }
Does compile | Does not compile
The following are statements about what kinds of trait implementations are permitted by Rust. Select each statement which is true.
Loesung: The “orphan rule” requires that you cannot implement an external trait for an external type, to ensure code doesn’t break if two crates provide conflicting implementations.
10.3
Which kind of programming error is a lifetime supposed to prevent?

Using a reference to an object after its memory has been freed
Using the result of a fallible computation before checking for the possibility of error
Not allocating enough memory for an object 
Indexing past the bounds of an array (buffer overflow)
Determine whether the program will pass the compiler. If it passes, write the expected output of the program if it were executed.
fn shortest<’a, ’b>(x: &’a str, y: &’b str) -> &’a str { if x.len() < y.len() { x } else { y } }
fn main() { println!(“{}”, shortest(“hello”, “rust”)); }
 This program:  DOES compile OR does NOT compile
Context: If the type signature says that the function must return a reference with lifetime ’a, then it would be invalid to return a reference with a different lifetime ’b, i.e. y here.
If a reference has a lifetime ’static, then this means:
Response  
Consider the following un-annotated function signature.
struct Foo<’a> { bar: &’a i32 }
fn baz(f: Foo) -> &i32 { /_ … _/ }
Will Rust accept this function signature? If so, what lifetimes will it infer?
Consider the following un-annotated function signature.
struct Foo<’a> { bar: &’a i32 }
// Foo changed to &Foo fn baz(f: &Foo) -> &i32 { /_ … _/ }
Will Rust accept this function signature? If so, what lifetimes will it infer?
Response  
Mit der angegebenen Signatur wird es nicht kompiliert. Wenn man es wie folgt aendert kompiliert es!
struct Foo<’a> {
bar: &’a i32,
}
// Foo changed to &Foo
// fn baz(f: &Foo) -> &i32 {
fn baz<’a>(f: &’a Foo<’a>) -> &’a i32 {
f.bar
}
fn main() {
let a = 42;
let F = Foo { bar: &a };
let r = baz(&F);
println!(“{r}”);
}
Abschliessend weitere 6 Fragen:
Ownership Inventory #3
Program 1:
1 /// Returns the n-th largest element in a slice 2 fn find_nth<T: Ord + Clone>(elems: &[T], n: usize) -> T { 3 elems.sort(); 4 let t = &elems[n]; 5 return t.clone(); 6 }
If you tried to compile this program, which of the following best describes the compiler error you would get?

Program 1:
/// Returns the n-th largest element in a slice fn find_nth<T: Ord + Clone>(elems: &[T], n: usize) -> T { elems.sort(); let t = &elems[n]; return t.clone(); }
Normally if you try to compile this function, the compiler returns the following error:
error[E0596]: cannot borrow *elems
as mutable, as it is
behind a &
reference –> test.rs:3:5 | 3 |
elems.sort(); | ^^^^^^^^^^^^ elems
is a &
reference, so the data it refers to cannot be borrowed a
Assume that the compiler did NOT reject this function. Which (if any) of the following programs would (1) pass the compiler, and (2) possibly cause undefined behavior if executed? Check each program that satisfies both criteria, OR check “None of these programs” if none are satisfying.
Response  - None of these programs
 let v = vec![5, 4, 3, 2, 1]; find_nth(&v, 0); println!(“{}”, v[0]); 
let v = vec![5, 4, 3, 2, 1]; let n = &v[0]; find_nth(&v, 0); println!(“{}”, n); 
let v = vec![5, 4, 3, 2, 1]; find_nth(&v, 10);
/// Returns the n-th largest element in a slice fn find_nth<T: Ord + Clone>(elems: &[T], n: usize) -> T { elems.sort(); let t = &elems[n]; return t.clone(); }
Of the following fixes (highlighted in yellow), which fix best satisfies these three criteria:
(die gelbe Einfaerbung fehlt leider)
Response
fn find_nth<T: Ord>(mut elems: Vec
fn find_nth<T: Ord + Clone>(elems: &mut [T], n: usize) -> T { elems.sort(); let t = &elems[n]; return t.clone(); }
fn find_nth<T: Ord + Clone>(elems: &[T], n: usize) -> T { let mut elems = elems.to_vec(); elems.sort(); let t = &elems[n]; return t.clone(); }
fn find_nth<T: Ord + Clone>(elems: &[T], n: usize) -> T { let mut elem_refs: Vec<&T> = elems.iter().collect(); elem_refs.sort(); let t = elem_refs[n]; return t.clone(); }
struct TestResult { /// Student’s scores on a test scores:
Vec
/// A possible value to curve all scores
curve: Option<usize>
}
impl TestResult {
pub fn get_curve(&self) -> &Option
/// If there is a curve, then increments all
/// scores by the curve
pub fn apply_curve(&mut self) {
if let Some(curve) = self.get_curve() {
for score in self.scores.iter_mut() {
*score += *curve;
}
}
}
}
If you tried to compile this program, which of the following best describes the compiler error you would get?
Response  
struct TestResult { /// Student’s scores on a test scores:
Vec
/// A possible value to curve all scores
curve: Option<usize>
}
impl TestResult {
pub fn get_curve(&self) -> &Option
/// If there is a curve, then increments all
/// scores by the curve
pub fn apply_curve(&mut self) {
if let Some(curve) = self.get_curve() {
for score in self.scores.iter_mut() {
*score += *curve;
}
}
}
}
Normally if you try to compile this function, the compiler returns the following error:
error[E0502]: cannot borrow self.scores
as mutable
because it is also borrowed as immutable –> test.rs:17:26 | 16 | if
let Some(curve) = self.get_curve() { | —————- immutable borrow occurs
here 17 | for score in self.scores.iter_mut() { | ^^^^^^^^^^^^^^^^^^^^^^
mutable borrow occurs here 18 | score += curve; | —— immutable
borrow later used here
Assume that the compiler did NOT reject this function. Which (if any) of the following programs would (1) pass the compiler, and (2) possibly cause undefined behavior if executed? Check each program that satisfies both criteria, OR check “None of these programs” if none are satisfying.
Response  - let mut result = TestResult { scores: vec![20, 50, 30], curve: Some(10) }; let x = &result.scores[0]; result.apply_curve(); println!(“{}”, x); 
None of these programs 
let mut result = TestResult { scores: vec![20, 50, 30], curve: Some(10) }; result.apply_curve(); println!(“{:?}”, result.scores); 
let mut result = TestResult { scores: vec![20, 50, 30], curve: Some(10) }; result.apply_curve();
struct TestResult { /// Student’s scores on a test scores:
Vec
/// A possible value to curve all scores
curve: Option<usize>
}
impl TestResult {
pub fn get_curve(&self) -> &Option
/// If there is a curve, then increments all
/// scores by the curve
pub fn apply_curve(&mut self) {
if let Some(curve) = self.get_curve() {
for score in self.scores.iter_mut() {
*score += *curve;
}
}
}
}
Of the following fixes (highlighted in yellow), which fix best satisfies these three criteria:
Reponse
pub fn apply_curve(&mut self) { if let Some(curve) = self.get_curve().as_ref() { for score in self.scores.iter_mut() { score += curve; } } }
pub fn apply_curve(&mut self) { if let Some(curve) = self.get_curve() { for score in self.scores.iter() { score += curve; } } }
pub fn apply_curve(&mut self) { if let Some(curve) = self.get_curve() { for score in self.scores.clone().iter_mut() { score += curve; } } }
pub fn apply_curve(&mut self) { if let Some(curve) = self.curve { for score in self.scores.iter_mut() { *score += curve; } } }
Tests
11.1
What is the annotation you add to a function to indicate that it’s a unit test?
Answer: ****__****
Let’s say you have a function with the type signature:
fn f(x: usize) -> Result<usize, String>;
And you want to test that f(0) should return Err(_). Which of the following is NOT a valid way to test that?
Response 
#[test] fn test() { assert!(match f(0) { Ok() => false,
Err() => true });
} 
#[test] #[should_panic] fn test() { f(0).unwrap(); }
- #[test] #[should_err] fn test() -> Result<usize, String> { f(0) } 
#[test] fn test() { assert!(f(0).is_err()); }
11.2
When running cargo test with no additional configuration, which of the following actions may not work correctly if done by multiple tests?
Response  
Writing text to a single file
Failing via panics
Logging strings to stdout 
Reading data from a single database
Consider a program with the following unit test:
#[test] fn test_the_logger() { /_ … _/ }
#[test] fn test_the_database() { /_ … _/ }
#[test] fn test_logger_and_database() { /_ … _/ }
What is the shortest string you can pass to cargo test
Response: ****_****
11.3
Which of the following is NOT a good reason to wrap unit tests in #[cfg(test)] mod tests { … }?
Response 
Building a CLI tool
Kein Quiz
Iterators and Closures
13.1
Which of the following best describes the rationale for why Rust will infer the types of arguments/returns for closures, but not top-level functions?
Response  
Rust permits pattern matching within closure arguments, including the use of the underscore. For example, you could write the following:
let f = |_| (); // sometimes called the “toilet closure” let s = String::from(“Hello”); f(s);
Which of the following best describes the relationship between f and s in this program?
Response  
f has no effect on s 
f reads s and then throws away the result
f causes s to be immediately dropped
f captures s in its environment
13.2
Which of the following best describes why iterators are described as “lazy”?
Response 
True/false: these two code snippets are semantically equivalent.
Snippet 1:
while let Some(x) = iter.next() { f(x); }
Snippet 2:
for x in iter { f(x); }
Response  
Determine whether the program will pass the compiler. If it passes, write the expected output of the program if it were executed.
fn main() { let v = vec![1, 2, 3, 4]; let a: Vec<> = v.iter().filter(|x: &&i32| x % 2 == 0).map(|x: &i32| x 2).collect(); let b: Vec<> = v.iter().map(|x: &i32| x * 2).filter(|x: &i32| x % 2 == 0).collect(); println!(“{} {}”, a[0], b[0]); }
This program:  DOES compile OR does NOT compile
13.3
Kein Quiz
13.4
Kein Quiz
More about Cargo and Crates.io
Tests?
Smart Pointer
15.1
Question 1
Determine whether the program will pass the compiler. If it passes, write the expected output of the program if it were executed.
fn main() { let mut n = 1; let b = Box::new(&mut n); **b += 1; println!(“{}”, n); }  This program:  DOES compile OR does NOT compile
Question 2
Say we have a program with a variable:
let x: [Box<(usize, usize)>; 4] = /_ … _/
For a compile target with a 64-bit architecture, what is the minimum possible size in memory (in bytes) of x on the stack? Write your answer in digits, e.g. 0, 1, so on.
Response:
15.2
Question 1
Determine whether the program will pass the compiler. If it passes, write the expected output of the program if it were executed.
use std::ops::Deref;
#[derive(Clone, Copy)] struct AccessLogger(i32); impl Deref for AccessLogger { type Target = i32; fn deref(&self) -> &Self::Target { println!(“deref”); &self.0 } }
fn main() { let n = AccessLogger(-1); let x = n + 1; let n2 = n; println!(“{} {}”, x, n) }  This program:  DOES compile OR does NOT compile
15.3
Question 1
Determine whether the program will pass the compiler. If it passes, write the expected output of the program if it were executed.
struct Example(i32); impl Drop for Example { fn drop(&mut self) { self.0 += 1; println!(“drop {}”, self.0); } }
fn main() { let e = Example(0); drop(e); drop(e); }  This program:  DOES compile OR does NOT compile
Question 2
Consider this snippet that allocates a string:
fn main() { let mut s = String::new(); ******___****** }
Which of the following are valid operations to fill in the underscore that would cause s to be dropped?
s.drop(); 
(|_| ())(s);
{ s };
drop(s);
15.4
Question 1
Determine whether the program will pass the compiler. If it passes, write the expected output of the program if it were executed.
use std::rc::Rc;
fn main() { let n = Rc::new(1); let mut n2 = Rc::clone(&n); *n2 += 1; println!(“{}”, n); }
This program: DOES compile OR does NOT compile
Question 2
Determine whether the program will pass the compiler. If it passes, write the expected output of the program if it were executed.
use std::rc::Rc;
struct Example; impl Drop for Example { fn drop(&mut self) { println!(“drop”); } }
fn main() { let x = Rc::new(Example);
let y = Rc::clone(&x);
println!(“A”); drop(x); println!(“B”); drop(y);
println!(“C”); }  This program:  DOES compile OR does NOT compile
15.5
Question 1
Which of the following best describes the concept of interior mutability in Rust?
Allowing data on the inside of a data structure to be mutated 
Allowing data to be mutated through an immutable reference 
Wrapping unsafe code in a safe API
Using the borrow checker to enforce memory safety at runtime
Question 2
Consider an API that tracks the number of calls to a particular method:
struct Api { count: ??? }
impl Api { fn some_method(&self) { // increment count // rest of
the method… }
}
Say the count is represented as a usize. Which of the following would be the most appropriate wrapper type to use for this situation? 
Box
Rc
None, usize is fine
-RefCell
Question 3
Consider the following incorrect implementation of a RefCell that does not check whether the interior value is borrowed:
use std::cell::UnsafeCell;
struct BadRefCell
Now say we have a BadRefCell like this:
let v = BadRefCell(UnsafeCell::new(vec![1, 2, 3]));
Which of the following snippets would violate memory safety using this API?
15.6
Question 1
Determine whether the program will pass the compiler. If it passes, write the expected output of the program if it were executed.
use std::rc::Rc;
fn main() { let r1 = Rc::new(0); let r4 = { let r2 = Rc::clone(&r1); Rc::downgrade(&r2) }; let r5 = Rc::clone(&r1); let r6 = r4.upgrade(); println!(“{} {}”, Rc::strong_count(&r1), Rc::weak_count(&r1)); }  This program:  DOES compile OR does NOT compile
Fearless concurrency
16.1
Question 1
Determine whether the program will pass the compiler. If it passes, write the expected output of the program if it were executed.
use std::thread; fn main() { let mut n = 1; let t = thread::spawn(move || { n = n + 1; thread::spawn(move || { n = n + 1; }) }); n = n + 1; t.join().unwrap().join().unwrap(); println!(“{n}”); }
[ ] Does compile [ ] Does not compile
Question 2
Consider this example from the text where a vector is improperly captured by a thread:
use std::thread; fn main() { let v = vec![1, 2, 3]; let handle = thread::spawn(|| { println!(“Here’s a vector: {:?}”, v); }); handle.join().unwrap(); } The Rust compiler includes this diagnostic:
note: function requires argument type to outlive 'static
–> src/main.rs:6:18 | 6 | let handle = thread::spawn(|| { |
********__********^ 7 | | println!(“Here’s a vector: {:?}”, v); 8 | |
}); | |**__**^
Recall that ’static is the lifetime of references that are valid for the entire program’s duration.
Which of the following best describes the note “function requires argument type to outlive ’static”?

16.2
Question 1 Determine whether the program will pass the compiler. If it passes, write the expected output of the program if it were executed.
use std::{sync::mpsc, thread}; enum ClientMessage { Incr, Get, Quit } enum ServerMessage { Get(usize) } fn main() { let (server_tx, client_rx) = mpsc::channel(); let (client_tx, server_rx) = mpsc::channel(); let server = thread::spawn(move || { let mut n = 0; loop { match server_rx.recv().unwrap() { ClientMessage::Quit => break, ClientMessage::Incr => n += 1, ClientMessage::Get => server_tx.send(ServerMessage::Get(n)).unwrap() } } }); for msg in [ClientMessage::Incr, ClientMessage::Get, ClientMessage::Quit] { client_tx.send(msg).unwrap(); } if let ServerMessage::Get(n) = client_rx.recv().unwrap() { println!(“{}”, n) } server.join().unwrap(); } 🐞 Response  This program:  DOES compileOR does NOT compile
Question 2
Determine whether the program will pass the compiler. If it passes, write the expected output of the program if it were executed.
use std::{sync::mpsc, thread}; fn main() { let (tx, rx) = mpsc::channel(); thread::spawn(move || { let s = String::from(“Hello world”); tx.send(s.clone()).unwrap(); tx.send(s.len()).unwrap(); }); let s = rx.recv().unwrap(); let n = rx.recv().unwrap(); println!(“{s} {n}”); } 🐞 Response  This program:  DOES compileOR does NOT compile
16.3
Question 1 In some concurrency APIs, a mutex is separate from the data it guards. For example, imagine a hypothetical Mutex API like this:
let mut data = Vec::new(); let mx: Mutex = Mutex::new(); { let _guard
= mx.lock(); data.push(0); } Which of the following best describes why
Rust uses Mutex

Question 2 Determine whether the program will pass the compiler. If it passes, write the expected output of the program if it were executed.
use std::{sync::Arc, thread}; fn main() { let s = String::from(“Hello world”); let a = Arc::new(&s); let a2 = Arc::clone(&a); let t = thread::spawn(move || a2.len()); let len = t.join().unwrap(); println!(“{} {}”, a, len); } 🐞 Response  This program:  DOES compileOR does NOT compile
16.4
Question 1
Imagine you are designing an API for a database connection like this:
struct DbConnection { /_ … / } impl DbConnection { fn query(&self) -> DbResult { / … _/ } }
Your database does not support concurrent queries from the same connection. Which of the following marker traits should DbConnection implement?

OO Features
Patterns and Matching
Patterns and Matching