rust - 实现迭代器时如何返回引用?

标签 rust iterator lifetime

我想返回对集合中拥有的对象的引用(即 Vec),但我似乎无法获得正确的生命周期。这是我第一次尝试的:

struct StringHolder {
    strings: Vec<String>,
    i: usize,
}

impl Iterator for StringHolder {
    type Item<'a> = &'a String;
    fn next(&mut self) -> Option<Self::Item> {
        if self.i >= self.strings.len() {
            None
        } else {
            self.i += 1;
            Some(&self.strings[self.i])
        }
    }
}

fn main() {
    let sh = StringHolder { strings: vec![], i: 0 };
    for string in sh {
        println!("{}", string);
    }
}

我收到一个错误,提示泛型关联类型不稳定 并且生命周期与特征中的类型不匹配。我尝试了其他几次迭代,但似乎没有任何效果。

根据我读过的一些东西,我认为这可能是不可能的,但后来我似乎无法弄清楚 Vec 是如何做到的。例如,我可以使用以下代码简单地迭代底层 Vec 并在每次迭代时返回一个引用:


struct StringHolder {
    strings: Vec<String>,
}

impl<'a> IntoIterator for &'a StringHolder {
    type Item = &'a String;
    type IntoIter = ::std::slice::Iter<'a, String>;
    fn into_iter(self) -> Self::IntoIter {
        (&self.strings).into_iter()
    }
}

fn main() {
    let sh = StringHolder { strings: vec!["A".to_owned(), "B".to_owned()] };
    for string in &sh {
        println!("{}", string);
    }
}

所以这让我觉得这是可能的,我只是还没有弄清楚生命周期。感谢您的帮助。

最佳答案

Iterator特征不包括 Item 的生命周期,这是您看到的错误之一。另一个暗示GATs这是一个不稳定的 Rust 特性。应用于此示例的 GAT 可让您将每次调用的项目生命周期限制为 next()而不是所有具有相同生命周期的项目。话虽如此,Iterator特征不太可能改变,因此这种更灵活的行为必须是新特征。

鉴于 Iterator 的设计trait,你不能让迭代器拥有它的数据并且拥有它的Item成为它的引用。只是没有一种方式来表达生命周期。

为了让项成为引用,迭代器的通常编写方式是让它们持有对基础数据的引用。这为数据提供了一个命名的生命周期,可以在关联的 Item 上使用。 . Vec 有点这样做,但有点不同,因为Vec实际上从 slice 得到它的迭代.

您的完整示例:

struct StringHolder {
    strings: Vec<String>,
}

struct StringHolderIter<'a> {
    string_holder: &'a StringHolder,
    i: usize,
}

impl<'a> Iterator for StringHolderIter<'a> {
    type Item = &'a str;
    fn next(&mut self) -> Option<Self::Item> {
        if self.i >= self.string_holder.strings.len() {
            None
        } else {
            self.i += 1;
            Some(&self.string_holder.strings[self.i - 1])
        }
    }
}

impl<'a> IntoIterator for &'a StringHolder {
    type Item = &'a str;
    type IntoIter = StringHolderIter<'a>;
    fn into_iter(self) -> Self::IntoIter {
        StringHolderIter {
            string_holder: self,
            i: 0,
        }
    }
}

关于rust - 实现迭代器时如何返回引用?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/68606470/

相关文章:

python迭代类似dict的对象

java - 为什么公开迭代器底层表示不好?

c - "static"变量的这个定义是错误的、误导性的还是两者都不是?

rust - 使用具有生命周期参数的关联类型特征的生命周期错误

rust - 方法返回具有相同生命周期的结构迭代器的生命周期

garbage-collection - 对范围垃圾收集建模的生命周期限制

rust - 在 Hyper 0.11 中找不到类型 `post` 的名为 `hyper::Client` 的方法

c++ - 当不知道通用 STL 容器的迭代器值类型时如何使用模板化迭代器?

c# - 如何将结构向量从 Rust 返回到 C#?

rust - 如何在 HashMap 字段中保存对处理程序的引用