so i’ve had the chance to try out some Rust programming for a project i’m working on. first of all: it comes as no surprise that Rust is one of the most loved languages in most polls i come across. it’s awesome and i love it. i’ve never been sceptical of Rust, so it’s hardly been a conversion for me, but i’ve found low-level languages quite hard to understand. besides most language’s inaccessibility towards beginners or self-taught developers, most languages also have (relatively) poor communities & packages compared to more modern interpreted languages imo, but i’d digress. 😩

ERROR HANDLING. i hate it most of the time. it’s scary. i never quite learned how to do it properly, i usually let someone else architect how it works and then follow their style. not with Rust, the language actually has really good defaults for error handling that i love

so im gonna try to explain this and get you up to speed to how certain things work with Rust. i’m assuming you know some basic programming terms.

errors happen, usually when you don’t want to, sometimes because you didn’t see it coming. in most cases, functions where something can go wrong return a thing called a Result. a Result is an enum which represents something that went fine with Ok or something that went wrong with Err. kind of a more complicated true or false representing if a function worked succesfully or not.

these enums also hold the value they’re representing like so:

// both these functions return a Result<u32, ParseError>
let works = "4".parse::<u32>(); // returns Ok(4)
let does_not_work = "j".parse::<u32>(); // returns Err(ParseError)

the program doesn’t crash when there’s an error, but Rust does expect you to handle the situation. you either have the choice of simply calling .unwrap() on the Result to crash in case it doesn’t work (or use .expect("<message>") to be a bit more explicit).

your other option would be to match the Result to its Ok and Err parts and handle the cases there.

let crashes = "hello".parse::<u32>().unwrap(); // crashes
let crashes_but_nicer = "hello".parse::<u32>()
     .expect("A number to parse."); // crashes with a message

let has_number_when_correct_exits_function_if_not = match "foobar".parse::<u32>() {
  Ok(number) => number,
  Err(error) => return Err(error)

the next best thing that i learned? that last statement with the match, has a shortcut that’s so nice to write. the ? operator. its simply expands to the above match statement. you can also use it in between accessors!

//this is the same as the previous `match` statement
let failed_parse_but_shorter = "foobar".parse::<u32>()?; // bubbles up Err(ParseError)
let two_the_power_of_four = "2".parse::<u32>()?.pow(4); // returns 16

small caveat: you can only use the ? operator if the function/method signature is the same as the error that you’re bubbling upwards.

// this function will compile
fn parse_and_add_two(some_value: &str) -> Result<u32, ParseError> { 
  let parse_value = some_value.parse::<u32>()?;

  parse_value + 2

// an example enum
enum HttpError {

//this function will not compile
fn get_http_number_and_add_two() -> Result<u32, HttpError> {
    let result: String = do_http_request()?;  // returns a number
    let parse_value = result.parse::<u32>()?; // will not compile
    // return type <u32, HttpError> != <u32, ParseError>

here comes the greatest part: you can convert one error to the other type so the code does compile! you just need to convert the ParseError to an HttpError and you’re done! with the std::convert::From trait you can do this easily like so:

use std::convert::From;

enum HttpError {

impl From<ParseError> for HttpError {
    fn from(error: ParseError) -> HttpError {

these things combine to be an awesome language that literally has a compiler dedicated to making sure you cover all these cases. i eliminated SO many edge cases and error cases because of this design decision on a LANGUAGE LEVEL. i love it

anyway, if that rambling made any sense to you, feel free to follow me on here or stalk me on other places on the internet.