Why can't a range of char be collected?
EDIT 2020-07-17: since Rust 1.45.0, the trait Step
is implemented for char
, making Range<char>
(and some other char ranges) work as an iterator. The code in the question now compiles without problem!
Old answer below.
The expression b'a'..=b'z'
has the type RangeInclusive<u8>
(see on Playground) because the expression b'a'
has the type u8
: that's what the b
in front of the character literal is for. On the other hand, the expression 'a'..='z'
(without the b
s) has the type RangeInclusive<char>
.
[...] there is a blanket implementation of
Iterator
forRangeInclusive
.
For one, this is not what we call "blanket implementation" (this is when the impl block is for T
or for &T
(or similar) with T
being a generic type). But yes, there is an impl. But let's take a closer look:
impl<A> Iterator for RangeInclusive<A>
where
A: Step, // <--- important
The A: Step
bound is important. As you can see in the documentation for Step
, this trait is implemented for all primitive integer types, but not for char
. This means that there is no clear "add one" operation on characters. Yes, you could define it to be the next valid Unicode codepoint, but the Rust developers probably decided against that for a good reason.
As a consequence, RangeInclusive<char>
does not implement Iterator
.
So your solution is already a good one. I would probably write this:
(b'a'..=b'z').map(char::from).collect::<Vec<_>>()
The only real advantage is that in this version, char
doesn't appear twice.
The problem was that the iteration capabilities of range types depend on the Step
trait (see extended answer).
However, starting from Rust 1.45, char
also implements Step
(PR 72413), which means that the code in the question now works!
let ascii_lowercase: Vec<char> = ('a'..='h').collect();
assert_eq!(
ascii_lowercase,
vec!['a', 'b', 'c', 'd', 'e', 'f', 'g', 'h'],
);