Rust flashcards: 50 essentials with code
Learn the Rust that the compiler keeps asking about: ownership, borrowing, lifetimes, Option and Result, traits, closures, smart pointers and async.
Practice now
Study without an account
Scheduled with the default Askesis timings. Progress is saved in this browser.
All 50 cards
- 1The three ownership rulesEach value has one owner; there is only one owner at a time; when the owner goes out of scope, the value is dropped
- 2What happens to
aafterlet b = a;whenais aString?The value moves tob; usingaafterwards is a compile errorerror[E0382]: borrow of moved value:a - 3Which types are copied instead of moved?Types that implement
Copy: integers, floats,bool,char, shared references, and tuples/arrays ofCopytypes - 4
CopyvsCloneCopyis an implicit bitwise copy for cheap types;Cloneis an explicit, possibly expensive.clone()EveryCopytype must also beClone. - 5The borrowing ruleAt any time you can have either one
&mut Tor any number of&T, and references must not outlive the value - 6Why doesn’t this compile?You can’t borrow
vmutably (push) while an immutable borrow (first) is still in userustlet mut v = vec![1, 2, 3]; let first = &v[0]; v.push(4); println!("{first}"); - 7
Stringvs&strStringis an owned, growable, heap-allocated buffer;&stris a borrowed view of UTF-8 text - 8Best parameter type for read-only text
&strA&Stringcoerces to&str, so the function accepts both. - 9Why can’t you index a
Stringwiths[0]?Strings are UTF-8, so a byte index may not be a character boundaryUses.chars().nth(0)or slice on a known boundary like&s[0..1]. - 10What does this signature say?The returned reference lives as long as the shorter of
xandyrustfn longest<'a>(x: &'a str, y: &'a str) -> &'a str - 11What does
'staticmean on a reference?The data lives for the whole program, like string literals - 12Lifetime elision with one reference inputThe output reference gets that input’s lifetime, so you don’t write it
- 13What is
Option<T>?Some(T)orNone: Rust’s way to model an absent value instead of null - 14What is
Result<T, E>?Ok(T)orErr(E): the return type for operations that can fail - 15What does the
?operator do?UnwrapsOk/Some, or returns theErr/Nonefrom the current function earlyrustfn read_config() -> Result<String, std::io::Error> { let text = std::fs::read_to_string("config.toml")?; Ok(text) } - 16How does
?convert error types?It callsFrom::fromon the error, so it works when the function’s error type implementsFrom<SourceError> - 17
unwrap()vsexpect("msg")Both panic onNone/Err;expectadds your message to the panic - 18
unwrap_orvsunwrap_or_elseunwrap_or(v)evaluatesveagerly;unwrap_or_else(|| v)only computes it when needed - 19Turn an
Optioninto aResultrustlet user = find_user(id).ok_or(Error::NotFound)?; - 20Are
matchexpressions required to be exhaustive?Yes. Every possible value must be covered, often with a_catch-all - 21Match one variant and ignore the restrust
if let Some(user) = maybe_user { greet(&user); } - 22
let ... elseDestructure or bail out with a diverging blockrustlet Some(port) = args.port else { return Err("missing port".into()); }; - 23Match guardAn extra
ifcondition on a match armrustmatch n { x if x < 0 => "negative", 0 => "zero", _ => "positive", } - 24What is a trait?A set of methods a type can implement, like an interface; traits can provide default methods
- 25Generic function with a trait boundrust
fn largest<T: PartialOrd + Copy>(items: &[T]) -> T - 26Same bound written with
whererustfn largest<T>(items: &[T]) -> T where T: PartialOrd + Copy, - 27
impl Traitin argument positionShorthand for a generic parameter:fn show(item: impl Display)accepts anyDisplaytype - 28
impl Traitin return positionReturns one concrete type that the caller only knows by its trait, e.g.-> impl Iterator<Item = u32> - 29Generics vs
dyn TraitGenerics are monomorphized (static dispatch, one copy per type);dyn Traituses a vtable at runtime (dynamic dispatch) - 30Store different types that share a trait in one
Vecrustlet shapes: Vec<Box<dyn Shape>> = vec![Box::new(Circle(1.0)), Box::new(Square(2.0))]; - 31The orphan ruleYou can implement a trait for a type only if your crate defines the trait or the type
- 32Which traits can
#[derive]give you?Standard ones likeDebug,Clone,Copy,PartialEq,Eq,Hash,PartialOrd,Ord,Default - 33
FnvsFnMutvsFnOnceFnborrows its captures,FnMutmutably borrows them,FnOncemay consume them and can be called once - 34What does
movedo on a closure?Forces the closure to take ownership of the variables it capturesrustlet name = String::from("ada"); std::thread::spawn(move || println!("{name}")); - 35Are iterator adapters like
mapandfiltereager?No, they’re lazy; nothing runs until a consumer likecollect,sumor aforloop drives them - 36Sum the squares of the even numbersrust
let total: i32 = nums.iter().filter(|&&n| n % 2 == 0).map(|&n| n * n).sum(); - 37
iter()vsiter_mut()vsinto_iter()Yields&T,&mut T, or ownedT(consuming the collection) - 38Collect an iterator of
Results, stopping at the first errorrustlet nums: Result<Vec<i32>, _> = input.lines().map(str::parse::<i32>).collect(); - 39When do you need
Box<T>?To put a value on the heap: recursive types, large values, or trait objects (Box<dyn Trait>) - 40
Rc<T>vsArc<T>Both are reference-counted shared ownership;Arcuses atomic counts and is safe to share across threads - 41What is
RefCell<T>?Interior mutability with borrow rules checked at runtime; a violation panicsCommon pattern for shared mutable data in one thread:Rc<RefCell<T>>. - 42Shared mutable state across threadsrust
let counter = Arc::new(Mutex::new(0)); *counter.lock().unwrap() += 1; - 43
SendvsSyncSend: ownership can move to another thread.Sync:&Tcan be shared between threads - 44Why isn’t
Rc<T>Send?Its reference count isn’t atomic, so two threads could corrupt it; useArc<T> - 45Library vs application error handlingLibraries usually define error enums (often with
thiserror); applications often useanyhow::Resultwith context - 46What does
unsafelet you do?Dereference raw pointers, callunsafefunctions (including FFI), access mutable statics, implementunsafetraits, access union fields - 47Does
unsafeturn off the borrow checker?No. It only allows those extra operations; you take responsibility for upholding the safety rules - 48What does an
async fnreturn?AFuture; nothing runs until it is.awaited or polled by an executor like Tokio - 49Make an item public and add a dependencyMark items
pubto export them; add crates withcargo add <crate>(written toCargo.toml) - 50
cargo checkvscargo buildchecktype-checks without producing a binary, so it’s much faster during development
Frequently asked questions
Is this deck for Rust beginners?
It suits anyone who has started the Rust book or written a little Rust. It focuses on the concepts that cause the most compiler errors.
Which Rust edition does it use?
Everything applies to the 2021 and 2024 editions of stable Rust.
Does it cover async Rust?
It covers the basics (futures and .await). Executors such as Tokio are only mentioned.
More in Programming
JavaScript
Master the JavaScript every developer uses daily: scope, closures, equality, array methods, promises, async/await and the event loop.
50 cardsAdvanced JS
Fifty advanced JavaScript cards: event-loop ordering puzzles, generators and async iteration, this binding, Proxy and Reflect, modules, AbortController and coercion edge cases.
50 cardsTypeScript
Learn the TypeScript you use every day: narrowing, generics, keyof, mapped and conditional types, utility types, satisfies and strict mode, with code on every card.
50 cardsPython
Learn idiomatic Python fast: comprehensions, f-strings, args and kwargs, generators, decorators, context managers and the standard library.
50 cardsGit & terminal
The Git commands and shell skills developers use every day: branching, rebasing, undoing mistakes, pipes, redirects, permissions and processes.
50 cardsJava
Core Java with short snippets: equals vs ==, records, sealed types, collections, generics, exceptions, streams, lambdas and JVM basics.
50 cardsC#
C# and .NET fundamentals with short snippets: value vs reference types, properties, records, nullable reference types, LINQ, async/await and DI.
50 cardsKotlin
Kotlin fundamentals with short snippets: null safety, val vs var, data and sealed classes, extension functions, scope functions and coroutines.
50 cardsSwift
Swift fundamentals with short snippets: optionals, structs vs classes, protocols, enums with associated values, closures, ARC, async/await and SwiftUI.
50 cardsFlutter
Flutter and Dart basics: null safety, futures and streams, stateless vs stateful widgets, setState, hot reload, keys, layout and state management.
50 cardsPHP
Modern PHP 8 with short snippets: strict types, arrays, match, nullsafe and named arguments, enums, readonly, Composer, PDO and password_hash.
50 cardsRuby
Ruby fundamentals with short snippets: blocks, procs and lambdas, symbols, Enumerable, mixins, truthiness, method_missing, gems and Bundler.
50 cardsGo
Go (Golang) fundamentals with short, idiomatic snippets: slices vs arrays, maps, defer, error wrapping, interfaces, goroutines, channels, select and context.
50 cardsC++
Modern C++ in short snippets: references vs pointers, RAII, smart pointers, move semantics, STL containers and algorithms, const, templates and UB.
50 cardsHaskell
Haskell fundamentals with short code: types and type classes, pattern matching, laziness, Maybe and Either, folds, Functor, Applicative and Monad.
50 cardsElixir
Elixir fundamentals with short snippets: immutability, pattern matching, the pipe operator, Enum vs Stream, processes, GenServer, supervisors and mix.
50 cardsx86-64 assembly
x86-64 assembly in Intel syntax: registers and sub-registers, flags, mov and lea, jumps, the stack frame, the System V calling convention and Linux syscalls.
50 cardsRegex
Learn regular expressions for good: anchors, classes, greedy vs lazy quantifiers, groups, lookarounds, flags, replacements and the backtracking trap.
50 cards