A1 Midterm 1 Review
Table of Contents:
- Revision 1 Changes
- Reminders about the exam
- Development Tools
- Shell/Terminal Commands
- Git Commands
- Cargo Commands
- Quick Questions: Tools
- Rust Core Concepts
- Variables and Types
- String vs &str
- Quick Questions: Rust basics
- Functions
- Loops and Arrays
- Enums and Pattern Matching
- Midterm Strategy
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 filesmkdir folder_name- make a foldercd folder_name- move into a foldercd ..- move up to a parent foldercd ~- return to the home directoryrm 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 linkgit status- see what's changedgit log- see the commit historygit branch- list all branchesgit checkout branch_name- switch to a different branchgit checkout -b new_branch- create a branch callednew_branchand switch to itgit add .- stage all recent changesgit commit -m "my commit message"- create a commit with staged changesgit push- send what's on my machine to GitHubgit pull- get changes from GitHub to my machinegit merge branch_name- merge branchbranch_nameinto 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 projectcargo run- compile and runcargo run --release- compile and run with optimizations (slower to compile, faster to run)cargo build- just compile without runningcargo check- just check for errors without compilingcargo 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 mutto allow them to change - Shadowing:
let x = x + 1;creates a newxvalue withoutmutand lets you change types - Basic types:
i32,f64,bool,char,&str,String - Rough variable sizes: Eg.
i32takes up 32-bits of space and its largest positive value is about half ofu32'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()orString::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 matchreturn_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;andxare 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..5vs1..=5 - Arrays: Creating (
[5,6]vs[5;6]), accessing (x[i]), 0-indexing - If/else: how to write
if / elseblocks with correct syntax - Loop types:
for,while,loop- how and when to use each breakandcontinue: For controlling loop flow- Basic enumerating
for (i, val) in x.iter().enumerate() - Compact notation (
let x = if y ...orlet 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
matchexpressions: 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, orexpect
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!