Hey, taking a shot on aoc2022 day5
I need to parse a part of String and pattern match + destructure three chars in order to build a structure.
Now this compiles but looks wasteful:
fn parse_crate(input: &str) -> Result<Crate, String> {
let chars: Vec<char> = input.chars().take(3).collect();
match chars[..] {
[_, c, _] => Ok(Crate(c)),
_ => Err("could not parse crate".into()),
}
}
So, intuitively I have tried to get rid of the vec:
fn parse_crate(input: &str) -> Result<Crate, String> {
// let chars: Vec<char> = input.chars().take(3).collect();
// match chars[..] {
match input[..=3] {
[_, c, _] => Ok(Crate(c)),
_ => Err("could not parse crate".into()),
}
}
which yells at me:
44 | [_, c, _] => Ok(Crate(c)),
| ^^^^^^^^^ pattern cannot match with input type `str`
what is going on here?
isn't the slicing operator [..] returns a str anyway in the first example?
what is the idiomatic way of doing this?
Thanks!
You cannot index a str or a String. It is that way because there is no sensible way to index a UTF-8 string.
For the AOC problem, it is adequate to convert the String to Vec<char>. If you want to avoid allocations, you can do something like:
let mut it = input.chars().take(3);
match (it.next(), it.next(), it.next()) {
(_, Some(c), _) => Ok(Crate(c)),
_ => Err("could not parse crate".into()),
}
You actually can index them with ranges. Our comrade is probably just misunderstanding the &str type.
&str is not an array of char, but just two usize’s, first of which is pointing to a buffer of bytes ([u8]) and second is just a length. Note that these bytes are not chars, and you probably need to use Chars iterator.
For AoC puzzles it's typically overkill to use strings because everything is ASCII; Vec<u8> / &[u8] / b"byte string literals" should suffice, or alternatively you can use str::as_bytes() to get a byte slice from a string.