loading...

Type Aliases in Rust

rpalo profile image Ryan Palo Originally published at assertnotmagic.com ・2 min read

I always forget about type aliases when I'm writing Rust code--mostly I get caught up in making it work mechanically and making the compiler happy and forget about readability. But yesterday, I was working through Advent of Code Day 3 challenge, and I remembered them. Just to see if they helped, I sprinkled them into my code, and I was shocked at how much better I felt about reading through what I had done.

Better readability, better self-documentation, less static to hold in mental memory at once.

Here's a snippet of the code before the transformation:

fn parse_input() -> (Vec<Coordinate>, Vec<Coordinate>) {
    let text = fs::read_to_string("data/day3.txt").unwrap();
    let lines: Vec<&str> = text.split("\n").collect();
    let mut wires = lines.into_iter().map(build_moves).map(make_wire);
    (wires.next().unwrap(), wires.next().unwrap())
}

/// Build a Wire out of relative Moves
fn make_wire(moves: Vec<Coordinate>) -> Vec<Coordinate> {
    let mut current = Coordinate { x: 0, y: 0 };
    let mut results: Wire = Vec::new();

    for step in moves {
        current = step + current;
        results.push(current);
    }

    results
}

// ...

Lots of Vectors full of Coordinates right? And some are global coordinates, and some are lists of relative steps from one coordinate to the next, so they're not conceptually the same "type" of Vec<Coordinate>. Messy, right?

Here's what it looks like after I add in my type aliases:

/// A Wire is a chain of coordinates that are electrically connected
type Wire = Vec<Coordinate>;

/// Moves are an ordered list of delta moves to make to form a wire
type Moves = Vec<Coordinate>;


fn parse_input() -> (Wire, Wire) {
    let text = fs::read_to_string("data/day3.txt").unwrap();
    let lines: Vec<&str> = text.split("\n").collect();
    let mut wires = lines.into_iter().map(build_moves).map(make_wire);
    (wires.next().unwrap(), wires.next().unwrap())
}

/// Build a Wire out of relative Moves
fn make_wire(moves: Moves) -> Wire {
    let mut current = Coordinate { x: 0, y: 0 };
    let mut results: Wire = Vec::new();

    for step in moves {
        current = step + current;
        results.push(current);
    }

    results
}

// ...

Now, even though Wire and Moves are made up of the same ingredients, they are separated conceptually for our brains to process, and our intent is documented much better.

This is my fourth attempt at learning Rust, and it's certainly feeling quite a bit better than any time before. So, yay for improvement!

Posted on by:

rpalo profile

Ryan Palo

@rpalo

Ryan is an engineer in the Sacramento Area with a focus in Python, Ruby, and Rust. Bash/Python Exercism mentor. Coding, physics, calculus, music, woodworking. Message me on DEV!

Discussion

markdown guide
 

Really good reminder and a nice and simple example. Thanks!

 

Great post! I didn't know about type aliases in rust

 

Thanks! Yeah they are great 👍🏻