I'm having a hard time understanding how the Split
type works in Rust.
Split<'a, P> where P: Pattern<'a>
is the type returned by the std::string::String::split
method. The type has an implementation for Iterator<'a, P>
, where P
is still the Pattern
type, but in reality (and as I would expect) the Iterator
only returns &str
slices.
E.g., split(p).collect::<Vec<&str>>()
works but split(p).collect::<Vec<char>>()
results a compiler error. This is what I would expect to happen, but I don't understand how it happens since Pattern
has implementations for both &str
and char
.
Why isn't the Split
type simply defined as Split<'a, &'a str>
, since it is effectively an Iterator
over &str
s? Why does it behave as if it is effectively defined as that?
The type has an implementation for
Iterator<'a, P>
It doesn't. It's just Iterator
, which has no type parameters. Every implementation of Iterator
must declare the type of the item that it iterates over using an associated type. For example, Split
's implementation[1] is something like this:
impl <'a, P> Iterator for Split<'a, P> {
type Item = &'a str;
fn next(&mut self) -> Option<&'a str> { ... }
}
Why isn't the
Split
type simply defined asSplit<'a, &'a str>
, since it is effectively anIterator
over&str
s?
Because iterators are lazy. The Split
struct still needs to know about the pattern in order to match the next item. Its iterator instance has Item = &str
, because that is what it iterates over.
[1]The actual implementation is generated by a macro.