In Rust you can use impl Trait in a return signature to simplify the return type. In addition, it allows you to statically represent the "unnamed concrete type" of closures.
It is pretty common to just see impl Iterator<Item = T> in the signature, which is much easier to write than the exact return type. In addition, I believe this also makes your API stable against any change to the type of the returned iterator. For instance, you could swap out a Vec (std::slice::Iter) for a VecDeque (std::collections::vec_deque::Iter).
However I just discovered that this has a significant drawback. In the case that you need access to methods provided by DoubleEndedIterator, ExactSizeIterator and FusedIterator you have now accidently reduced the features of your returned iterator.
Consider this example on the Rust playground...
#[derive(Clone, Debug, Default, Eq, PartialEq)]
struct NewVec<T>(Vec<T>);
impl<T> NewVec<T> {
    pub fn iter(&self) -> impl Iterator<Item = &T> + DoubleEndedIterator {
        self.0.iter()
    }
}
fn main() {
    let palindrome = NewVec(Vec::from(['R', 'A', 'C', 'E', 'C', 'A', 'R', '!']));
    println!("{:?}", palindrome);
    println!(
        "{}",
        palindrome
            .iter()
            .map(|character| format!("{}", character))
            .collect::<Vec<String>>()
            .join("")
    );
    println!(
        "{}",
        palindrome
            .iter()
            .rev()
            .map(|character| format!("{}", character))
            .collect::<Vec<String>>()
            .join("")
    );
}
The iter method on NewStruct cannot just return impl Iterator<Item = &T>, instead must return impl Iterator<Item = &T> + DoubleEndedIterator in order for rev to work.
This isn't the end of the world, but now signatures are impl Iterator<Item = &T> + DoubleEndedIterator + ExactSizeIterator + FusedIterator in order to avoid a reduction in the features of the returned iterator.
Is there a better way to achieve this? Do I really have to add impl Iterator<Item = &T> + DoubleEndedIterator + ExactSizeIterator + FusedIterator on every function return type that returns an iterator if I do not want to restrict the underlying iterator?
Does this also imply that there may also be a performance impact in cases whereby the returned iterator does not specify that it also implements ExactSizeIterator and FusedIterator, even though underlying iterator actually does implement these traits?
There is no way to make trait aliases at the moment. Type aliases do not work for traits and a trait alias can be emulated with trait inheritance, however this introduces a new type which now needs to be exported.
You can omit FusedIterator, since, as noted in the docs, it should not be used in bounds but rather used as specialization in fuse(), and specializations can "see through" impl Trait.
You can also omit Iterator, since it is a supertrait of both DoubleEndedIterator and ExactSizeIterator.
Which leaves us with these shorter bounds:
pub fn iter(&self) -> impl DoubleEndedIterator<Item = &T> + ExactSizeIterator {
    self.0.iter()
}
                        If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With