Debug for AnyIterable (why IntoIter and not Iter)

I am reading the book "Rust for Rustaceans" and on page 33 J. Gjengset gives an example for a excessively generic implementation of Debug for any iterable collection:

impl Debug for AnyIterable

  where for<'a> &'a Self: IntoIterator,
  where for<'a> &'a Self as IntoIterator>::Item: Debug {

    fn fmt(&self, f: &mut Formatter) -> Result<(), Error> {
         // The bounds are needed for `entries(...)`.
         f. debug_list().entires(self).finish()
    }
}

I tried to implement this to try it out and I stumbled across the following questions which
are unclear to me.

  • IntoIterable should be meant for constructing a consuming iterator. But you can implement it on
    on value types (truely consuming) or reference types (which would then just be the same as iter()).

So I came up with this example:

#![feature(impl_trait_in_assoc_type)]
use std::{fmt::Debug, iter::Flatten, sync::Arc};

struct Store {
    a: Vec<i32>,
}

impl<'a> IntoIterator for &'a Store {
    type Item = &'a i32;
    type IntoIter = impl Iterator<Item = Self::Item>;

    fn into>_iter(self) -> Self::IntoIter {
        println!("refimpl");    
        (&self.a).into_iter()
    }
}

impl IntoIterator for Store {
    type Item = i32;
    type IntoIter = impl Iterator<Item = Self::Item>;

    fn into_iter(self) -> Self::IntoIter {
        println!("valueimpl");
        self.a.into_iter()
    }
}

impl Debug for Store
where
    Self: IntoIterator,
    <Self as IntoIterator>::Item: Debug,
{
    fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
        f.debug_list().entries(self).finish()
    }
}

fn main() {
    let i = Store { a: vec![1, 3, 4] };
    for v in &i {
        println!("{:?}", v);
    }
    for v in i {
        println!("{:?}", v);
    }
}

As I see I dont even need the higher-ranked trait bound. Whats the difference between
the one J. Gjengset proposes and the one I coded, they work the same or is there some culprit?

You don't even need any bounds at all on impl Debug for Store, because Store is not generic.

I don’t own Rust for Rustaceans, so I can’t check, but I think there must be some context here that your quote leaves out. What is the definition of AnyIterable? The only thing that could make the bounds relevant here, without changing the quoted code, is if it has an elided lifetime parameter. Other than that possibility, the impl is not generic so it doesn’t need bounds.

Presuming you mean IntoIterator: this is not true. It is simply the case that IntoIterator takes Self by value; whether that is really “consuming” anything significantly entirely depends on what Self is.

1 Like