A1 Midterm 1 Review

Table of Contents:

Revision 1 Posted Oct 7.

Changes:

  • Enabled Rust playground for all code blocks
  • In Loops and Arrays, modified what is not important and important
  • Deleted quesiton 15 about Some(x) and renumbered remaining questions
  • Updated code slightly in new question number 16

Reminders about the exam

  • Practice exam posted on Piazza
  • Up to 5 pages of notes, double sided, any font size
  • No electronic devices
  • Bring a pencil!
  • Spread out -- don't sit beside or in front or behind anyone

Development Tools

Shell/Terminal Commands

For the midterm, you should recognize and recall:

  • pwd - where am I?
  • ls - what's here?
  • ls -la - more info and hidden files
  • mkdir folder_name - make a folder
  • cd folder_name - move into a folder
  • cd .. - move up to a parent folder
  • cd ~ - return to the home directory
  • rm filename - delete a file

You DON'T need to: Memorize complex command flags or advanced shell scripting

Git Commands

For the midterm, you should recognize and recall:

  • git clone - get a repository, pasting in the HTTPS or SSH link
  • git status - see what's changed
  • git log - see the commit history
  • git branch - list all branches
  • git checkout branch_name - switch to a different branch
  • git checkout -b new_branch - create a branch called new_branch and switch to it
  • git add . - stage all recent changes
  • git commit -m "my commit message" - create a commit with staged changes
  • git push - send what's on my machine to GitHub
  • git pull - get changes from GitHub to my machine
  • git merge branch_name - merge branch branch_name into the current branch

You DON'T need to: revert, reset, resolving merge conflicts, pull requests

Cargo Commands

For the midterm, you should recognize and recall:

  • cargo new project_name - create project
  • cargo run - compile and run
  • cargo run --release - compile and run with optimizations (slower to compile, faster to run)
  • cargo build - just compile without running
  • cargo check - just check for errors without compiling
  • cargo test - run tests

You DON'T need to know: Cargo.toml syntax, how Cargo.lock works, advanced cargo features

Quick Questions: Tools

Question 1

Which command shows your current location on your machine?

Question 2

What's the correct order for the basic Git workflow?

  • A) add → commit → push
  • B) commit → add → push
  • C) push → add → commit
  • D) add → push → commit

Question 3

Which cargo command compiles your code without running it?

Rust Core Concepts

Compilers vs Interpreters

Key Concepts

  • Compiled languages (like Rust): Code is transformed into machine code before running
  • Interpreted languages (like Python): Code is executed line-by-line at runtime
  • The compiler checks your code for errors and translates it into machine code
  • The machine code is directly executed by your computer - it isn't Rust anymore!
  • A compiler error means your code failed to translate into machine code
  • A runtime error means your machine code crashed while running

Rust prevents runtime errors by being strict at compile time!

Variables and Types

Key Concepts

  • Defining variables: let x = 5;
  • Mutability: Variables are immutable by default, use let mut to allow them to change
  • Shadowing: let x = x + 1; creates a new x value without mut and lets you change types
  • Basic types: i32, f64, bool, char, &str, String
  • Rough variable sizes: Eg. i32 takes up 32-bits of space and its largest positive value is about half of u32's largest value
  • Type annotations: Rust infers types (let x = 5) or you can specify them (let x: i32 = 5)
  • Tuples: Creating (let x = (2,"hi")), accessing (let y = x.0 + 1), destructuring (let (a,b) = x)
  • Arrays: Creating (let x = [1,2,3]), accessing (let y = x[1])
  • Accessing and indexing elements of arrays, tuples and enums.

What's Not Important

  • Calculating exact variable sizes and max values
  • 2's complement notation for negative integers
  • Complex string manipulation details

String vs &str

Quick explanation

  • String = a string = owned text data (like a text file you own)
  • &str = a "string slice = borrowed text data (like looking at someone else's text)
  • A string literal like "hello" is a &str (you don't own it, it's baked into your program)
  • To convert from an &str to a String, use "hello".to_string() or String::from("hello")
  • To convert from a String to an &str, use &my_string (to create a "reference")

Don't stress! You can do most things with either one, and we won't make you do anything crazy with these.

Quick Questions: Rust basics

Question 4

What happens with this code?

#![allow(unused)]
fn main() {
let x = 5;
x = 10;
println!("{}", x);
}
  • A) Prints 5
  • B) Prints 10
  • C) Compiler error
  • D) Runtime error

Question 5

What's the type of x after this code?

#![allow(unused)]
fn main() {
let x = 5;
let x = x as f64;
let x = x > 3.0;
}
  • A) i32
  • B) f64
  • C) bool
  • D) Compiler error

Question 6

How do you access the second element of tuple t = (1, 2, 3)?

  • A) t[1]
  • B) t.1
  • C) t.2
  • D) t(2)

Functions

Key Concepts

  • Function signature: fn name(param1: type1, param2: type2) -> return_type, returned value must match return_type
  • Expressions and statements: Expressions reduce to values (no semicolon), statements take actions (end with semicolon)
  • Returning with return or an expression: Ending a function with return x; and x are equivalent
  • {} blocks are scopes and expressions: They reduce to the value of the last expression inside them
  • Unit type: Functions without a return type return ()
  • Best practices: Keep functions small and single-purpose, name them with verbs

What's Not Important

  • Ownership/borrowing mechanics (we'll cover this after the midterm)
  • Advanced function patterns

Quick Questions: Functions

Question 7

What is the value of mystery(x)?

#![allow(unused)]
fn main() {
fn mystery(x: i32) -> i32 {
    x + 5;
}
let x = 1;
mystery(x)
}
  • A) 6
  • B) i32
  • C) ()
  • D) Compiler error

Question 8

Which is a correct function signature for a function that takes two integers and returns their sum?

Question 9

Which version will compile

#![allow(unused)]
fn main() {
// Version A
fn func_a() {
    42
}

// Version B
fn func_b() {
    42;
}
}
  • A) A
  • B) B
  • C) Both
  • D) Neither

Question 10

What does this print?

#![allow(unused)]
fn main() {
let x = println!("hello");
println!("{:?}", x);
}
  • A) hello \n hello
  • B) hello \n ()
  • C) hello
  • D) ()
  • E) Compiler error
  • F) Runtime error

Loops and Arrays

Key Concepts

  • Ranges: 1..5 vs 1..=5
  • Arrays: Creating ([5,6] vs [5;6]), accessing (x[i]), 0-indexing
  • If/else: how to write if / else blocks with correct syntax
  • Loop types: for, while, loop - how and when to use each
  • break and continue: For controlling loop flow
  • Basic enumerating for (i, val) in x.iter().enumerate()
  • Compact notation (let x = if y ... or let y = loop {...)
  • Labeled loops, breaking out of an outer loop

What's Not Important

  • Enumerating over a string array with for (i, &item) in x.iter().enumerate()

Quick Questions: Loops & Arrays

Question 11

What's the difference between 1..5 and 1..=5?

Question 12

What does this print?

#![allow(unused)]
fn main() {
for i in 0..3 {
    if i == 1 { continue; }
    println!("{}", i);
}
}

Question 13

How do you get both index and value when looping over an array?

Enums and Pattern Matching

Key Concepts

  • Enum definition: Creating custom types with variants
  • Data in variants: Enums can hold data
  • match expressions: syntax by hand, needs to be exhaustive, how to use a catch-all (_)
  • #[derive(Debug)]: For making enums printable
  • Data extraction: Getting values out of enum variants with match, unwrap, or expect

Quick Questions: Enums & Match

Question 14

What's wrong with this code?

#![allow(unused)]
fn main() {
enum Status {
    Loading,
    Complete,
    Error,
}

let stat = Status::Loading;

match stat {
    Status::Loading => println!("Loading..."),
    Status::Complete => println!("Done!"),
}
}

Question 15

What does #[derive(Debug)] do?

Question 16

What does this return when called with divide_with_remainder(10, 2)?

How about with divide_with_remainder(10, 0)?

#![allow(unused)]
fn main() {
enum MyResult {
    Ok(u32,u32),  // Store the result of the integer division and the remainder
    DivisionByZero,
}
fn divide_with_remainder(a: u32, b: u32) -> MyResult {
    if b == 0 {
        MyResult::DivisionByZero
    } else {
        MyResult::Ok(a / b, a % b)
    }
}
}

Midterm Strategy

  • Focus on concepts: Understand the "why" behind the syntax and it will be easier to remember
  • Practice with your hands: Literally and figuratively - practice solving problems, and practice on paper
  • Take bigger problems step-by-step: Understand each line of code before reading the next. And make a plan before you start to hand-code

Good Luck!