如何为自定义的IntoIterator :: Item实现std :: fmt :: Display?

时间:2017-03-28 22:54:32

标签: rust

LimitedFifoQueue是一个结构,它包含VecDeque的功能,以限制它随时存储的项目数:

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();
    }
}

我已按照以下方式实施IntoIterator特征:

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()
    }
}

一个简化的函数循环并打印每个项目:

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

这给了我以下错误:

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

我创建了一个带有完整堆栈跟踪here的代码的游乐场。

另外,我知道可能有更好的方法来完成我想要做的事情。我很乐意听到任何其他建议。

2 个答案:

答案 0 :(得分:3)

  

如何为自定义std::fmt::Display实施IntoIterator::Item

你做不到。 Item可能是您不拥有的类型,Display是您不拥有的特质。 You cannot implement a trait you don't own for a type you don't own

您所能做的就是要求Item实施Display

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

您不需要在数据结构或其方法上使用任何其他T: Display边界,因为这些实现都不会打印出值。

顺便说一句,{for-loops参数会自动调用into_iter,所以你只需说:

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

您可能还希望审核How to implement Iterator and IntoIterator for a simple struct?,因为您将&lfq传递到print_all,但&LimitedFifoQueue并未实施IntoIteratorLimitedFifoQueue。这些是不同的类型。你需要像

这样的东西
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()
    }
}

答案 1 :(得分:2)

此问题与您的IntoIterator实施或其他类型定义无关。请看一下这段代码:

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

这段代码甚至不知道您的LimitedFifoQueue类型!它采用泛型I的值。我们对I了解多少?它实现了IntoIterator。太好了,这告诉我们迭代器吐出的值是什么?没事!

所以它可能是任何东西,特别是那些没有实现fmt::Display的东西。所以我们要做的是注释迭代器的项至少应该实现fmt::Display。怎么做的?通过向Item特征的关联类型IntoIterator添加绑定:

fn print_all<I>(lines: &I)
    where I: IntoIterator,
          I::Item: fmt::Display,
{ ... }

一旦你明白你也可以为相关项添加界限,这是直观的。

修复该错误后,将报告另一个错误,即&#34;移出借来的内容&#34;。这是一个相当标准的错误,我在这里不会详细解释。但总结一下:您的print_all()函数应该收到I而不是&I