如何指定引用自身但不会自我变异的迭代器的关联类型的生存期?

时间:2017-06-25 14:55:29

标签: rust lifetime

我有这个结构:

struct RepIter<T> {
    item: T
}

我想为它实现Iterator,以便每次都返回对item的引用:

impl<T> Iterator for RepIter<T> {
    type Item = &T;
    fn next(&mut self) -> Option<Self::Item> {
        return Some(&self.item);
    }
}

这不会编译,因为必须为type Item = &T;指定生命周期。正在寻找一种方法,我找到了this question。第一种解决方案似乎并不适用,因为我实现了预先存在的特征。试图直接复制第二个解决方案我得到这样的东西:

impl<'a, T> Iterator for &'a RepIter<T> {
    type Item = &'a T;
    fn next(self) -> Option<&'a T> {
        return Some(&self.item);
    }
}

这不起作用,因为我需要一个可变的self作为next的参数。我能够编译它的唯一方法就是这样写:

impl<'a, T> Iterator for &'a RepIter<T> {
    type Item = &'a T;
    fn next(&mut self) -> Option<&'a T> {
        return Some(&self.item);
    }
}

但现在self是对引用的引用,对吧?我不知道如何在next的实例上致电RepIter。例如,这不起作用:

fn main() {
    let mut iter: RepIter<u64> = RepIter { item: 5 };
    let res = iter.next();
}

这让我觉得我的特质实现可以用更好的方式编写。

3 个答案:

答案 0 :(得分:3)

在设计迭代器时,为集合迭代器提供不同类型的集合通常很有用。通常,集合将拥有数据,迭代器将从集合中借用。集合类型通常实现IntoIterator并且不实现Iterator。这意味着创建迭代器分两步进行:我们需要先创建集合,然后从集合中创建迭代器。

这是一个将RepIter类型转换为集合的解决方案。我将使用Shepmaster的命题来使用iter::repeat来生成迭代器。

use std::iter::{self, Repeat};

struct RepIter<T> {
    item: T,
}

impl<T> RepIter<T> {
    // When IntoIterator is implemented on `&Self`,
    // then by convention, an inherent iter() method is provided as well.
    fn iter(&self) -> Repeat<&T> {
        iter::repeat(&self.item)
    }
}

impl<'a, T> IntoIterator for &'a RepIter<T> {
    type Item = &'a T;
    type IntoIter = Repeat<&'a T>;

    fn into_iter(self) -> Self::IntoIter {
        self.iter()
    }
}

fn main() {
    let iter: RepIter<u64> = RepIter { item: 5 };

    let res = iter.iter().next();
    println!("{:?}", res);

    let res = iter.iter().fuse().next();
    println!("{:?}", res);

    let res = iter.iter().by_ref().next();
    println!("{:?}", res);
}

答案 1 :(得分:2)

正如Shepmaster所链接的question中所讨论的那样,这有点棘手,因为你真的想要改变next()的类型,但是你不能因为它而不是部分特征。但是有几种方法可以解决这个问题。

对代码进行微小的更改,您只需使用Iterator上的&'a RepIter<T>实现:

pub fn main() {
    let mut iter = RepIter { item: 5 };
    let res = (&iter).next();
}

虽然有点不愉快。

另一种看待这种情况的方法是更改​​商品的所有权。如果已经借用了,那么你可以很好地匹配所有类型:

struct RepIter<'a, T: 'a> {
    item: &'a T,
}

impl<'a, T> Iterator for RepIter<'a, T> {
    type Item = &'a T;
    fn next(&mut self) -> Option<&'a T> {
        Some(&self.item)
    }
}

pub fn main() {
    let val: u64 = 5;
    let mut iter = RepIter { item: &val };
    let res = iter.next();
}

答案 2 :(得分:2)

我建议您将代码编写为:

Iterator

我还不太了解的一件事是你的现有代码几乎有效,但只适用于某些self方法;那些按值struct RepIter<T> { item: T, } impl<'a, T> Iterator for &'a RepIter<T> { type Item = &'a T; fn next(&mut self) -> Option<&'a T> { return Some(&self.item); } } fn main() { let iter: RepIter<u64> = RepIter { item: 5 }; // Works let res = iter.fuse().next(); println!("{:?}", res); // Doesn't work let res = iter.by_ref().next(); println!("{:?}", res); } 而不是参考的那些!

var customerRecord = r.Load({
    "type": r.Type.CUSTOMER,
    "id": recordId,
    "isDynamic": true
});

可能会发生一些有趣的互动。