Advent of Code 2017 Day 1 Using Advent of Code as a source of toy problems for my first dabblings in Rust. Looking for feedback from more-seasoned Rustaceans on usage of the language.

Advent of Code Day 1: Inverse Captcha

use std::fs::File;
use std::io::prelude::*;

fn get_input() -&gt; Vec&lt;u8&gt; {
    let mut file = File::open("input.txt").unwrap();
    let mut content = Vec::new();

    file.read_to_end(&amp;mut content).unwrap();
    for i in 0 .. content.len() {
        content[i] = content[i] - ('0' as u8);
    }

    content
}

fn offset_sum(input: &amp;[u8], offset: usize) -&gt; i32 {
    let len = input.len();
    let mut sum = 0;

    for i in 0 .. len {
        let j = (i + offset) % len;
        if input[i] == input[j] {
            sum += input[i] as i32;
        }
    }

    sum
}

fn main() {
    let input = get_input();

    println!("Part 1 total: {}", offset_sum(&amp;input, 1));
    println!("Part 2 total: {}", offset_sum(&amp;input, input.len()/2));
}
To be honest, for a simple, one-off problem, I disagree that hardcoding an input file name is disadvantageous. Similarly for error handling; you know the file is there and will read fine, so unwrapping it is fine; if it fails for some stupid reason there's no recovery you can do anyway.

And because the problem is so simple, there's not much to go about complaining about. This is a perfectly fine solution, because it's very readable.

But there are a few places where the standard library could be better utilized: (Note: I may go a little far here. Go as far iterator as you feel comfortable.)

The iteration over content's indices in get_input can be replaced by a mutating iterator:

for byte in &amp;mut content {
    *byte -= b'0';
}


Here I've also used a byte character literal, rather than casting to u8, which clippy will warn you about. With a known constant, it's safe, but then you should just use the byte literal.

What this says is to, for each position in content, take the thing at the position *byte, and decrement (-=) it by b'0'. It's the exact same as what you did, except without the manual indexing. (It's probably lowered to the same machine code in the end, but iterators are fun!)

offset_sum provides a more interesting field for refactoring, though. It can be done in one iterator chain by cleverly utilizing the available tools.

input


Start with the slice,

    .iter()


and get an iterator from it.

    .cloned()


Since we're operating over a Copy type, I dereference it here for convenience. If we just call iter, we get an iterator over &amp;u8, but calling cloned clones each element, which in this case is just a cheap Copy. Don't go doing this with non-copy types, though; this is just a convenience.

    .enumerate()


We pair up each byte with its index in the iterator.

    .filter(|&amp;(i, b)| b == input[(i + offset) % input.len()])


Filter out all of the numbers that don't match our requirements.

    .map(|(_, b)| u32::from(b))


Map our iterator back to just the number we care about. Convert it to a u32 so that we can

    .sum()


it into a u32 and consume the iterator.

Try it Online!

Some fun extensions you might try:

This is always going to be an \$O(n)\$ algorithm because you have to scan the whole string. But rather than handle indices, in the first half you could use  windows to grab each neighboring pair of bytes, though you will have to handle wraparound somehow. In the second half, you can reduce the number of comparisons you have to do by half, because each number is compared against the same number in either direction (the absolute opposite of a circular buffer). Maybe you can split the slice into two halves, then zip the two halves together for comparisons?