Enums, Option & Pattern Matching
Enums that carry data, Option instead of null, and match / if let to take them apart.
Rust enums are far more powerful than C's: each variant can hold different data. Together with match they model 'one of several kinds of thing' precisely — a CAN frame is a data frame, a remote frame, an error or an overload, never a mixture. Option<T> uses the same idea to replace null pointers.
Frames and optional values
Frame::Data { id, bytes } has named fields; Frame::Error(String) holds one value; Frame::Overload holds nothing.
match destructures each variant; the guard if bytes.is_empty() picks out empty data frames first.
find_sensor returns Option<&str>: Some(name) or None. The caller cannot use the name without handling None.
if let handles just one pattern; unwrap_or and map handle common cases without a full match.
Why Option beats null
let name = find_sensor(id).unwrap(); // in production code match find_sensor(id) { Some(n) =>..., None =>... } // or ? / unwrap_or unwrap panics on None. Keep it for tests and prototypes; handle the None case in real code.
What does Option<T> replace, and why is it safer?
Nullable pointers/references. The type system distinguishes 'maybe a T' from 'definitely a T', so code must handle None explicitly before using the value.
What happens if a match on an enum misses a variant?
It does not compile (error E0004, non-exhaustive patterns), unless a _ arm covers the rest.