Search code examples
genericsrustiteratortraitsassociated-types

Why does the Split type only return &str even though Pattern has implementations for both &str and char?


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 &strs? Why does it behave as if it is effectively defined as that?


Solution

  • 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 as Split<'a, &'a str>, since it is effectively an Iterator over &strs?

    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.