Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

How can I implement std::fmt::Display for a custom IntoIterator::Item?

Tags:

rust

LimitedFifoQueue is a struct that wraps the functionality of a VecDeque to limit the number of items it will store at any time:

use std::collections::{vec_deque, VecDeque};
use std::fmt;
use std;

#[derive(Debug)]
pub struct LimitedFifoQueue<T> {
    size: usize,
    store: VecDeque<T>,
}

impl<T> LimitedFifoQueue<T> where T: fmt::Display {
    pub fn new(size: usize) -> LimitedFifoQueue<T> {
        LimitedFifoQueue {
            size: size,
            store: VecDeque::with_capacity(size),
        }
    }
    pub fn push(&mut self, elem: T) {
        self.store.push_front(elem);
        if self.store.len() > self.size {
            self.store.pop_back();
        }
    }
    pub fn clear(&mut self) {
        self.store.clear();
    }
}

I've implemented the IntoIterator trait as follows:

impl<T> IntoIterator for LimitedFifoQueue<T> where T: fmt::Display {
    type Item = T;
    type IntoIter = vec_deque::IntoIter<T>;
    fn into_iter(self) -> Self::IntoIter {
        self.store.into_iter()
    }
}

And a simplified function that loops through and prints each Item:

fn print_all<I>(lines: &I) where I: IntoIterator {
    for string in lines.into_iter() {
        println!("{}", string);
    }
}

This gives me the following error:

println!("{}", string);
               ^^^^^^ the trait `std::fmt::Display` is not implemented for `<I as std::iter::IntoIterator>::Item`

I have created a playground of the code with a full stack trace here.


Also, I'm aware that there may be a better way to accomplish what I'm trying to do. I'd love to hear any additional suggestions.

like image 633
Patrick Allen Avatar asked Sep 05 '25 03:09

Patrick Allen


1 Answers

How can I implement std::fmt::Display for a custom IntoIterator::Item?

You cannot. Item might be a type you don't own, and Display is a trait you don't own. You cannot implement a trait you don't own for a type you don't own.

All you can do is require that Item implements Display:

fn print_all<I>(lines: I)
    where I: IntoIterator,
          I::Item: fmt::Display, 
{
    for string in lines.into_iter() {
        println!("{}", string);
    }
}

You don't need any of the other T: Display bounds on your data structure or its methods, as none of those implementations care to print out a value.

Incidentally, into_iter is automatically called on the for-loops argument, so you only need to say:

fn print_all<I>(lines: I)
    where I: IntoIterator,
          I::Item: fmt::Display, 
{
    for string in lines {
        println!("{}", string);
    }
}

You may also wish to review How to implement Iterator and IntoIterator for a simple struct?, as you are passing &lfq into print_all, but &LimitedFifoQueue doesn't implement IntoIterator, only LimitedFifoQueue does. These are different types. You'll need something like

impl<'a, T> IntoIterator for &'a LimitedFifoQueue<T> {
    type Item = &'a T;
    type IntoIter = vec_deque::Iter<'a, T>;
    fn into_iter(self) -> Self::IntoIter {
        self.store.iter()
    }
}
like image 77
Shepmaster Avatar answered Sep 07 '25 20:09

Shepmaster