Knowledge Checks
This page covers the material up to Midterm 1.
The intent of this page is to give you progressively more difficult challenges that you should master as the course progresses. You should attempt these with no notes, references or AI assistance, as you won't have those on the quizzes.
Don't move to the next challenge in each section until you have mastered the previous one.
If a section is marked with a prerequisite section, completed that first!
Knowledge checks are updated to cover up to Midterm 1.
Shell Commands
Prerequisite: None
In zsh or bash shell...
How do you print the current working directory in bash or zsh?
How do you switch into a different directory?
How do you list contents of a directory?
How do you list detailed contents of a directory, including file permissions?
What do the first 10 letters represent in the detailed file listings?
drwxr-xr-x@ 33 tgardos staff 1056 Feb 3 09:49 book
-rw-r--r--@ 1 tgardos staff 1438 Jan 21 14:59 book.toml
What does tgardos and staff represent in the detailed file listings?
drwxr-xr-x@ 33 tgardos staff 1056 Feb 3 09:49 book
-rw-r--r--@ 1 tgardos staff 1438 Jan 21 14:59 book.toml
How do you list hidden files and directories in a directory?
What naming convention renders a file hidden?
What do the special characters . and .. represent in file paths?
How do you recall previous commands at the command line?
Hint: You can see previous commands with one keypress.
How do you list the most recently used commands?
Hint: This will print out a list of the most recent commands you issued.
Git Commands
Prerequisite: Shell Commands
How do you clone a repository?
After you clone a repo, are you in the local repo or do you have to switch to it?
How do you list the branches in a repository?
How do you switch to a different branch?
How do you create a new branch?
How do you check whether you have modified or untracked files in a git repository?
How do you stage changes in your repository?
Hint: You are adding them to the staging area.
How do you commit changes to your repository along with a commit message in one step?
How do you merge a branch into the main branch?
How do you push changes to a remote repository?
How do you pull changes from a remote repository?
Working with a remote repository
What is the sequence of git and shell commands to:
- clone a repository, use the placeholder
<repository_url>, - make a topic branch called
hotfix - edit a file called
main.rs(just use the placeholder<edit main.rs>), - then all the remaining steps to stage the changes, commit the changes, push the changes to GitHub,
- use the placeholder
<create a pull request, approve and merge the pull request>, and - get the changes into the local repository's main branch
- delete the topic branch
Creating and working with a local repository
Show the sequence for:
- creating a directory called
my_rust_project - switch into the directory
- initialize as a git repository
- create a branch called
hotfix - editing a file called
main.rs(just use the placeholder<edit main.rs>) - staging the changes
- commit the changes with a commit message
- switch to the main branch and merge the hotfix branch into it
- deleting the hotfix branch
Rust Command Line Tools
Prerequisite: Shell Commands
How do you create a new Rust project?
How do you build a Rust project?
How do you run a Rust program?
How do you check if your project uses idiomatic Rust?
How do you correct common formatting issues in your Rust project?
Create and run a Rust projec using Cargo commands
Show the command sequence for:
- Creating a new Rust project called
my_rust_project - Switch into the project directory
- Build the project (and verify no compiler errors)
- Run the project
Select all statements that are true about Cargo commands:
-
cargo runcompiles and runs your program. -
cargo checkverifies compilation quickly without producing a runnable binary. -
cargo build --releaseplaces optimized output undertarget/release. -
cargo newcan only be used inside an existing Cargo project.
Basic Rust Syntax
Hello World in Rust
From memory, write a main function in Rust that prints "Hey world! I got this!".
Variables and Mutability
Variable Declaration in Rust
From memory, write a main function with variable declarations in Rust that prints the following:
- declares a variable called
nof typei32and assigns it the value5 - declares a variable called
xof typef32and assigns it the value3.14 - declares a variable called
resultof typef64and assigns it the valuen * x - Prints the string "5 * 3.14 = 15.7", and would update correctly for any other values
of
nandx
Create a program that:
- creates a u8 variable n with value 77
- creates an f32 variable x with value 1.25
- prints both numbers
- multiplies them and puts the results in an f64 variable result
- prints the result
Example output:
77
1.25
77 * 1.25 = 96.25
Mutable Variables
Write a main function with a mutable variable declaration in Rust that prints the following:
- declares a mutable variable called
nof typei32and assigns it the value5 - prints the value of
n - increments the value of
nto10 - prints the value of
n
Variable Shadowing and Scopes
From memory, write a main function that initializes a variable y to 42, then start a scope block with a variable y initialized to 3.14 and print that variable, then end the scope block and print y again.
Find the bug and fix it
fn main() { let x : i16 = 13; let y : i32 = -17; // won't work without the conversion println!("{}", x * y); }
Find the bug and fix it
fn main() { let x:f32 = 4.0; let z:f64 = 1.25; println!("{:.1}", x * z); }
Create a program that:
- Creates an unsigned int x with value 19 and a signed int y with value -5
- Prints both numbers in binary format (use {:08b} for 8-bit display)
- Performs bitwise AND (&) and prints the result in binary
- Performs bitwise OR (|) and prints the result in binary
- Performs bitwise NOT (!) on both numbers and prints the results
Show what the expected output would be as well.
String and string slice
Create a program that:
- Creates a
Strings1with value "Hello, " - Creates a string slice
s2with value "World!" - Creates a String
s3that is the concatenation ofs1ands2 - Prints the value of
s3
Show what the expected output would be as well.
Note: There is actually a subtlety here that we purposely avoided but you can try out yourself by making
s1a string slice and see what happens. It has to to do with ownership and borrowing which we cover later.
Indexing into a string and Chars
Create a program that:
- Creates a string slice
swith value "Hello, World!" - Prints the first character of
s - Prints the last character of
s - Prints the third character of
s
Create a program that:
- Creates an integer variable
xwith value 10 - Creates a boolean variable
is_positivewith valuex > 0 - Prints the value of
is_positive - Creates a boolean variable
is_negativewith valuex < 0 - Prints the value of
is_negative - Creates a boolean variable
is_zerowith valuex == 0 - Prints the value of
is_zero
Conditional Expressions
Predict the exact output of this Rust program.
fn main() { let n = 4; if n % 2 == 0 { println!("even"); } else { println!("odd"); } println!("{}", n + 1); }
Write a main function that:
- creates a variable
thresholdwith value 5 - creates a variable
valinitialized to 10 - then using print statements, if
valis less than threshold, print "val is less than threshold" - otherwise, print "val is greater than or equal to threshold"
- test it again with
val= 3
fn main() { }
Conditional Expressions with a return value
Challenge: Ticket Pricing Based on Age
Write a program that uses a conditional expression with a Stringreturn value to calculate ticket prices:
- Age < 5: free ("Free")
- Age between 5 and 17: child ticket ($10)
- Age between 18 and 64: adult ticket ($20)
- Age 65 or older: senior ticket ($12)
Print a message indicating the person's age and their ticket price.
fn main() { }
Functions
Write a function say_hello that takes a name and prints "Hello, {name}!".
Write a function say_hello_format that takes a name and returns a string "Hello, {name}!".
Write a function calculate_area that takes a length and width as f64 and returns the area of a rectangle as f64. Call the function from main and print the result.
Loops and Arrays
Select all statements that are true about loop constructs in Rust:
-
foris commonly used to iterate over collections like arrays. -
whileis useful when iteration depends on a changing condition. -
matchcan replace all loops in Rust. -
loopis an unconditional loop that can be exited withbreak.
Write a main function that prints all the multiples of n for numbers from 1 to m.
You can initialize n to 5 and m to 10.
In a main function, write a for loop to print the numbers from 12 to 0, skipped by 3.
Finding prime numbers
Write a main function that takes a starting and ending number and prints all the prime numbers in the range inclusive of starting and ending range.
Hint: This is a an example of a short algorithm. Recall a number is prime if it is greater than 1 and has no divisors other than 1 and itself. There's no point in checking for divisors greater than the square root of the number because if there is a divisor greater than the square root, then there was also a divisor less than the square root so we would have already determined that the number is not prime. You can calcuate square root of floating point number with the
sqrtmethod of thef64type as inx.sqrt().
Ticket Pricing Based on Age in a Loop
Loop over an array of ages and print the ticket price for each age
Write a program that uses a loop to calculate the ticket price for each age in the array [3, 10, 30, 70]:
- Age < 5: free ("Free")
- Age between 5 and 17: child ticket ($10)
- Age between 18 and 64: adult ticket ($20)
- Age 65 or older: senior ticket ($12)
Print a message indicating the person's age and their ticket price.
While Loop
Write a main loop that initializes a variable num to 10 and decrements it by 1 until it reaches 0. Print the value of num in each iteration.
Predict the exact output of this Rust program.
fn main() { let mut x = 1; let result = loop { if x % 3 == 0 { x = x+1; continue; } println!("X is {}", x); x = x + 1; if x==9 { break x*2; } }; println!("Result is {}", result); }
Predict the exact output of this Rust program.
fn main() { let mut x = 1; 'outer_loop: loop { 'inner_loop: loop { x = x + 1; if x % 5 != 0 { continue 'outer_loop; } if x > 15 { break 'outer_loop; } } }; println!("Managed to escape! :-) with x {}", x); }
Predict the exact output of this Rust program.
fn main() { let mut x = 1; 'outer_loop: loop { println!("Hi outer loop"); 'inner_loop: loop { println!("Hi inner loop"); x = x + 1; if x % 2 != 0 { break 'inner_loop; } println!("In the middle"); if x >= 4 { break 'outer_loop; } println!("X is {}", x); } println!("In the end"); }; println!("Managed to escape! :-) with x {}", x); }
Tuples
Tuples
In a main function, create a tuple with the values 1, 2, and 3 and debug print it as a single entity. Show what the expected output would be as well.
Accessing Tuple Elements
Create a tuple with the values 1, 2, and 3 and access the second element.
For let tuple = (10, 20, 30);, the first element is accessed as tuple.___ and
the third element is accessed as tuple.___.
Returning a Tuple from a Function
Write a function find_min_max_average that takes and array of 5 i32 values
and returns a tuple of (min, max, average) of the values as datatype (i32, i32, f64).
Hint: take note that you are producing a floating point average from an integer sum and length, so think about what you have to do there.
Write a main function that tests the function by initializing and array to be
[37, 42, 56, 12, 9], passing it to the function and then printing the results,
without debug printing -- either destructuring the tuple or indexing into the
tuple.
Enums and Match
Basic Enum and Exhaustive Match
Define an enum Direction with variants North, East, South, and West.
Write a function abbrev(dir: Direction) -> &'static str that uses match to return:
"N"forNorth"E"forEast"S"forSouth"W"forWest
Don't worry about the
'staticlabel for now. Just know that this function will return a static string slice.
Write a main function that calls abbrev with Direction::East and prints the result.
Match with Wildcard Arm
Define an enum Status with variants Pending, InProgress, Completed, and Failed.
Write a function is_finished(status: Status) -> bool using match such that:
Completedreturnstrue- all other variants return
false
Write a main function that tests the function with Status::Completed and Status::Pending.
Enum Variant with Data
Define an enum DivisionResult with variants:
Ok(u32, u32)for quotient and remainderDivisionByZero
Write a function divide_with_remainder(x: u32, y: u32) -> DivisionResult.
- If
y == 0, returnDivisionByZero - Otherwise return
Ok(x / y, x % y)
In main, call the function with 10 and 3, then use match to print either:
quotient=<q>, remainder=<r>- or
cannot divide by zero
Struct-Like Enum Variant
Define this enum:
#![allow(unused)] fn main() { enum Message { Quit, Move { x: i32, y: i32 }, Write(String), } }
The main difference between this enum and the previous one is that this one has a variant with a struct-like data type, in this case Move { x: i32, y: i32 }
with the curly braces. It works like the previous enum variant with a tuple,
but now we can give each field a name. You would initialize it like let msg = Message::Move { x: 4, y: -2 };.
Write a function describe(msg: Message) that uses match to print:
QuitMove to (x, y)forMove { x, y }Write: <text>forWrite(text)
In main, call describe with Message::Move { x: 4, y: -2 }.
Single-Branch Matching with if let
Define an enum:
#![allow(unused)] fn main() { enum Direction { North, East, South, West, } }
In main, create let dir = Direction::West; and use if let with an else branch to print:
Going Westwhen the value isWestNot Westotherwise
Select all statements that are true about match in Rust:
-
matchmust be exhaustive over possible cases. -
The wildcard arm (
_) can stand in for any remaining unmatched variants. -
The wildcard arm can only appear as the first arm in a
match. -
If you do not cover all variants (or use
_), the code will fail to compile.
Select all statements that are true about if let:
-
if letis convenient when you only care about one specific pattern. -
if letcan be paired withelsefor a fallback branch. -
if letrequires==for pattern matching comparisons. -
if letcan reduce verbosity compared to a fullmatchwith many ignored arms.
Select all statements that are true about pattern matching syntax in Rust:
-
In
if let, a single=is used with a pattern. -
==tests value equality and is not the pattern-matching operator. -
if let Some(x) == valueis valid Rust pattern matching syntax. -
In a
match, each arm uses a pattern followed by=>.
In a match expression, the wildcard pattern ___ is commonly used as a
catch-all for remaining cases.
In if let pattern matching, Rust uses the ___ operator for matching (not
the equality operator).
Ownership in Rust
Prerequisite: Complete Basic Rust Syntax
System Concepts
Language Properties
Rust language has:
- static data types
- dynamic data types
Python language has:
- static data types
- dynamic data types
Rust language memory management is:
- manual
- garbage collected
- ownership-based
Python language memory management is:
- manual
- garbage collected
- ownership-based
Select all that are true about Rust language:
- it is object-oriented
- is imperative
- is functional
- is declarative/logic
Numeric Representation
Indicate which base the following number systems are in:
The decimal number system is base ________.
The binary number system is base ________.
The octal number system is base ________.
The hexadecimal number system is base ________.
Convert the following numbers to decimal:
The binary number 0b0110_0101 is equivalent to the decimal number ________.
The binary number 0b1000_1010 (as i8) is equivalent to the decimal number ________.
The hexadecimal number 0x1A is equivalent to the decimal number ________.
The octal number 0o15 is equivalent to the decimal number ________.