Search code examples
rustiteratortraitsmove-semanticsborrow-checker

Why into_iter can be called on an iterator reference?


I can implement Iterator trait for my struct, and get IntoIterator implemented for free, thanks to the blanket implementation.

struct Foo {}

impl Iterator for Foo {
    type Item = ();
    fn next(&mut self) -> Option<Self::Item> { None }
}

fn bar(foo: Foo) {
    foo.into_iter(); // implemented automatically for my struct
}

But why can I also do this?

fn bar(foo: &mut Foo) {
    foo.into_iter(); // works; but shouldn't into_iter require ownership?
}

The implementation of the into_iter method seems to require ownership of the value:

impl<I: Iterator> const IntoIterator for I {
    type Item = I::Item;
    type IntoIter = I;

    #[inline]
    fn into_iter(self) -> I {
        self
    }
}

What allows the method into_iter to accept mutable reference when it is defined to take ownership?

Is there a way to make the method move_out in the following example to behave like the method into_iter?

trait A {}
trait B {
    fn move_out(self) -> Self;
}

impl<T: A> B for T {
    fn move_out(self) -> Self {
        self
    }
}

struct Foo {}
impl A for Foo {}

fn bar(foo: &mut Foo) {
    foo.move_out(); // compile error
}

Solution

  • It's pretty straight forward any type T that implements Iterator also implements Iterator for &mut T. And all types implementing Iterator implement IntoIterator which allows you to call into_iter on them in the first place.

    You can make A and B behave the same way by simply adding the same blanket implementation Iterator has:

    impl<T: A> A for &mut T {}
    

    Playground