类型不匹配将迭代器Item解析为具有显式生存期的指针

时间:2017-11-16 12:43:35

标签: iterator rust lifetime

我尝试将函数添加到Iterator,其中关联类型Item是对具有明确生命周期的结构的引用。

当我想要修改迭代器状态或返回新值时,我没有遇到任何问题,但是当我尝试返回新的IteratorItem是具有显式生命周期的引用,编译器抱怨。

实施例

use std::marker::PhantomData;

/// First, an "Inner" struct to be contained in my custom iterator
pub struct Inner {
    text: String,
}

/// Then, the "CustomIterator" in question.  Notice that `Item` is `&'a Inner`.
pub struct CustomIterator<'a, I: Iterator<Item = &'a Inner>> {
    iter: I,
    _marker: PhantomData<&'a i8>,
}

/// Implementing Iterator for CustomIterator so as to define the `next()` function, as you do...
impl<'a, I: Iterator<Item = &'a Inner>> Iterator for CustomIterator<'a, I> {
    type Item = &'a Inner;
    fn next(&mut self) -> Option<Self::Item> {
        println!("Custom next called");
        self.iter.next()
    }
}

/// Now, creating a custom trait definition called IterateMore that:
///   1. inherits Iterator
///   2. includes a default method called `more` which returns a `CustomIterator`
pub trait IterateMore<'a>: Iterator {
    type Item;
    fn more(self) -> CustomIterator<'a, Self>
    where
        Self: Sized;
}

/// Implementing `IterateMore` for an iterator of the specific type `Iterator<Item=&'a Inner>`
impl<'a, I: Iterator<Item = &'a Inner>> IterateMore<'a> for I
where
    I: Iterator,
{
    type Item = &'a Inner;
    fn more(self) -> CustomIterator<'a, Self>
    where
        Self: Sized,
    {
        CustomIterator {
            iter: self,
            _marker: PhantomData,
        }
    }
}

fn main() {
    let inner = Inner {
        text: "Hello world".to_string(),
    };
    let inners = vec![&inner];
    inners.iter().more().next();
}

(见repl.it

错误

error[E0271]: type mismatch resolving `<Self as std::iter::Iterator>::Item == &'a Inner`
  --> src/main.rs:28:5
   |
28 | /     fn more(self) -> CustomIterator<'a, Self>
29 | |     where
30 | |         Self: Sized;
   | |____________________^ expected associated type, found reference
   |
   = note: expected type `<Self as std::iter::Iterator>::Item`
              found type `&'a Inner`
   = note: required by `CustomIterator`

为什么Item在这里无法解决?这有点令人沮丧,因为如果我尝试将&'a Inner设置为特征定义中的默认Item类型,编译器也会抱怨:

error: associated type defaults are unstable (see issue #29661)

如何修复或以不同方式完成?

1 个答案:

答案 0 :(得分:2)

我不清楚为什么你想要将包装的迭代器限制为某种自定义类型(假设你每次使用该类型时仍然必须记下限制,尽管这可能会改变)。但也许你的“真正的”next函数会做一些有趣的事情。

  • PhantomData似乎不再需要(使用)在where - 条款中使用它时的生命周期。
  • IterateMore不应该有Item个关联类型,只有Iterator已经拥有它。 (如果你真的需要一个新类型选择一个不同的名字)
  • 由于IterateMore使用CustomIterator类型,因此需要重复要求,在本例中为Iterator<Item = &'a Inner>(这就是类型不匹配错误的含义);这与在特质定义中说type Item = &'a Inner不同。

Playground

/// an "Inner" struct to be contained in my custom iterator
pub struct Inner {
    text: String,
}

pub struct CustomIterator<'a, I>
where
    I: Iterator<Item = &'a Inner>,
{
    iter: I,
}

impl<'a, I> Iterator for CustomIterator<'a, I>
where
    I: Iterator<Item = &'a Inner>,
{
    type Item = I::Item;
    fn next(&mut self) -> Option<Self::Item> {
        println!("Custom next called");
        self.iter.next()
    }
}

pub trait IterateMore<'a>: Iterator<Item = &'a Inner> + Sized {
    fn more(self) -> CustomIterator<'a, Self>;
}

impl<'a, I> IterateMore<'a> for I
where
    I: Iterator<Item = &'a Inner>,
{
    fn more(self) -> CustomIterator<'a, Self> {
        CustomIterator { iter: self }
    }
}

fn main() {
    let inner = Inner {
        text: "Hello world".to_string(),
    };
    let inners = vec![inner];
    inners.iter().more().next();
}

您也可以在此处删除类型限制(并且只将其添加回您实际需要/想要的位置):

Playground

pub struct CustomIterator<I> {
    iter: I,
}

impl<I> Iterator for CustomIterator<I>
where
    I: Iterator,
{
    type Item = I::Item;
    fn next(&mut self) -> Option<Self::Item> {
        println!("Custom next called");
        self.iter.next()
    }
}

pub trait IterateMore: Iterator + Sized {
    fn more(self) -> CustomIterator<Self>;
}

impl<I> IterateMore for I
where
    I: Iterator,
{
    fn more(self) -> CustomIterator<Self>
    {
        CustomIterator { iter: self }
    }
}

fn main() {
    let inners = vec!["Hello world".to_string()];
    inners.iter().more().next();
}