IntoIterator on a reference of a type

I have a type A and I implemented the IntoIterator trait on &A. Now I have the following snippet:

let a = A::new();

let mut iter = a.into_iter();
loop
{
      match iter.next() {
          Some(val) => println!("value {}", val),
          None => break
      }
}
    
  for i in &a
  {
      println!("for loop value {}", i);
  }

The compiler seems to invoke the into_iter() implemented on the reference type A. Can I infer that in the absence of the implementation of the IntoIterator trait on A the compiler will pick the implementation on the reference?

Thanks in advance.

Mostly yes. The exact rules are stated here in the Rust reference.
The gist is that during a method call resolution, the type of the receiver object, here A, is both referenced and de-referenced. There is a specific ordering, which is not super useful unless you want to answer David Tolnay's quiz correctly. Hence, although a is of type A, since the method into_iter exists for &A, it is picked up.
This is no different from you calling an impl method on something which is the type itself, not a reference.

...and doesn't exist for A, that's important too (otherwise Vec::into_iter wouldn't be called in the similar case).

2 Likes

You haven’t implemented the Trait method into_iter for your owned type OR you haven’t created an iter method for you collection (collection -> a type that implements Iterator). If you rely on inference, you need 3 versions of into_iter (3 separate Trait impls); the inference for which (collection -> iterator) is then made based on the rights you have with the collection (encoded in the type and used to lookup the appropriate trait implementation).

The into_iter Trait method for each of owned, exclusive borrow and borrow all take ownership (per the into_iter naming convention semantic move into), of the value, exclusive ref and non-exclusive ref respectively* [1].

Separately, you can opt to create methods: into_iter, iter_mut and iter in a impl block of your collection [2].

Here is a link to a document that describes iterators many found useful. It describes the different ways for building an iterator for your collection.


  1. a dynamic that is obfuscated when refs themselves impl copy, thus avoiding or making moot what would otherwise require a move ↩︎

  2. which can be used for the into_iter if the return type doesn’t already impl IntoIterator ↩︎

Another important piece of information is that it’s not really important what the Self-type of the impl … or impl …trait… for … block is, but only what the type of the self argument is.

I.e. there is no special rule that only fn …(&self, …) methods or fn …(&mut self, …) methods in an impl Foo or impl SomeTrait for Foo block can be called on a variable x: Foo, but - as demonstrated by the IntoIterator example, it could also be a fn …(self, …) method in an impl SomeTrait for &Foo (or some indirectly / generically implemented trait).


This also means there is - in practice - a backwards compatibility problem with adding such an impl for A later. Now, the documented rules for what’s considered “breaking” changes allow breakage related to method resolution AFAIR, but it’s still able to cause problems: one particular example was the IntoIterator impl for [T; N] that was added to the standard library. Breakage to existing foo.into_iter() calls on foo: [T; N] that used to produce slice::Iter<'_, T> iterators of &foo was considered a large enough concern that special-case rules (modifying method resolution) were introduced to the compiler that kept the old behavior for into_iter on arrays in all but the latest 2021 edition.

As an aside, note that it's very weird behavior for a .into_*() call to not consume the receiver, in that it's at least at the surface inconsistent with naming conventions.
It's not inherent to that example though, more of a side effect of how the IntoIterator trait works.

This topic was automatically closed 90 days after the last reply. We invite you to open a new topic if you have further questions or comments.