My solutions to the 2019 Advent of Code edition in Rust.
I am a Rust noob so I am probably going to do these challenges using the following process:
- Write an ugly and inefficient solution that works.
- Look at other people's solutions to
shamelessly copylearn and be inspired by their code. - Rewrite my solutions.
To run the code for a solution just jump into a directory and build/run it:
$ cd day01
$ cargo run --release < input/input.txt
The solutions include tests. To run all of them quickly you can do something like:
$ for f in day??/Cargo.toml; do cargo test --release --manifest-path=$f; done
Saturating arithmetic operations is much sexier than manually checking for and handling over-/underflow.
Use the successors function to create an iterator where each successive item is computed based on the preceding one.
Use filter_map to, well, filter and map.
Very useful with ok which converts a Result<T, E>
into Option<T>
(and thus dicarding the error).
Mainly: don't overengineer! Apart from that I didn't see any major differences (that I liked) in other people's solutions.
A small thing I learned was using &[T]
over &Vec<T>
in function parameters.
The only time you want to use &Vec<T>
is if you for some reason need to read the vector's capacity.
If you want to change the vector you'd have to use &mut Vec<T>
anyway (ref. Steve
Klabnik).
Improved performance quite a bit by using HashSet
(and the
intersection method) instead of
Vec
.
Learned to implement the Hash and PartialEq traits.
Still not sure about Eq
vs PartialEq
and Ord
vs PartialOrd
. Probably need to see it more in the wild to
understand when and why to use them.
Some other subjects that still are fuzzy: reference vs value, iter
vs into_iter
, all the different ok
, ok_or
,
or_else
, ok_or_else
, unwrap_or
, unwrap_or_else
, etc. Probably mixing Option
and Result
here.
Lifetimes are still pretty much terra incognita so I basically try avoid them for now. Same for all that trait stuff in functions (apparently they are called bounds).
Found a great answer on
StackOverflow
on how to return an Iterator
from a function. To summarize: use impl
trait or Box
(if the return
type is decided dynamically). Can
also use newtype or type
aliases.
Use Default. Itertools for permutations and other cool functional stuff which aren't in the std yet.
Was a simple answer on the iter
vs into_iter
on
StackOverflow:
iter()
iterates over the items by referenceinto_iter()
iterates over the items, moving them into the new scopeiter_mut()
iterates over the items, giving a mutable reference to each item
But looking at other answers it seems to be at bit more complicated (and context dependent).