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 run compiles and runs your program.
  • cargo check verifies compilation quickly without producing a runnable binary.
  • cargo build --release places optimized output under target/release.
  • cargo new can 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 n of type i32 and assigns it the value 5
  • declares a variable called x of type f32 and assigns it the value 3.14
  • declares a variable called result of type f64 and assigns it the value n * x
  • Prints the string "5 * 3.14 = 15.7", and would update correctly for any other values of n and x





Create a program that:

  1. creates a u8 variable n with value 77
  2. creates an f32 variable x with value 1.25
  3. prints both numbers
  4. multiplies them and puts the results in an f64 variable result
  5. 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 n of type i32 and assigns it the value 5
  • prints the value of n
  • increments the value of n to 10
  • 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:

  1. Creates an unsigned int x with value 19 and a signed int y with value -5
  2. Prints both numbers in binary format (use {:08b} for 8-bit display)
  3. Performs bitwise AND (&) and prints the result in binary
  4. Performs bitwise OR (|) and prints the result in binary
  5. 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:

  1. Creates a String s1 with value "Hello, "
  2. Creates a string slice s2 with value "World!"
  3. Creates a String s3 that is the concatenation of s1 and s2
  4. 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 s1 a 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:

  1. Creates a string slice s with value "Hello, World!"
  2. Prints the first character of s
  3. Prints the last character of s
  4. Prints the third character of s



Create a program that:

  1. Creates an integer variable x with value 10
  2. Creates a boolean variable is_positive with value x > 0
  3. Prints the value of is_positive
  4. Creates a boolean variable is_negative with value x < 0
  5. Prints the value of is_negative
  6. Creates a boolean variable is_zero with value x == 0
  7. 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:

  1. creates a variable threshold with value 5
  2. creates a variable val initialized to 10
  3. then using print statements, if val is less than threshold, print "val is less than threshold"
  4. otherwise, print "val is greater than or equal to threshold"
  5. 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:

  • for is commonly used to iterate over collections like arrays.
  • while is useful when iteration depends on a changing condition.
  • match can replace all loops in Rust.
  • loop is an unconditional loop that can be exited with break.

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 sqrt method of the f64 type as in x.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" for North
  • "E" for East
  • "S" for South
  • "W" for West

Don't worry about the 'static label 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:

  • Completed returns true
  • 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 remainder
  • DivisionByZero

Write a function divide_with_remainder(x: u32, y: u32) -> DivisionResult.

  • If y == 0, return DivisionByZero
  • 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:

  • Quit
  • Move to (x, y) for Move { x, y }
  • Write: <text> for Write(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 West when the value is West
  • Not West otherwise

Select all statements that are true about match in Rust:

  • match must 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 let is convenient when you only care about one specific pattern.
  • if let can be paired with else for a fallback branch.
  • if let requires == for pattern matching comparisons.
  • if let can reduce verbosity compared to a full match with 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) == value is 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 ________.