简体   繁体   English

返回对内部集合的引用时的迭代器生命周期问题

[英]Iterator lifetime issue when returning references to inner collection

I have a struct that lazily load data into an inner vector (but for the example this is ommited).我有一个结构,可以将数据延迟加载到内部向量中(但对于示例,这是省略的)。 Then I am implementing IntoIterator and Iterator for the IntoIterator type:然后我为 IntoIterator 类型实现IntoIteratorIterator

struct EntryOwned(u32);
struct Entry<'a>(&'a u32);

impl<'a> EntryOwned {
    fn to_entry(&'a self) -> Entry<'a> {
        Entry(&self.0)
    }
}

struct LazyStruct {
    cache: Vec<EntryOwned>,
}

impl<'a> LazyStruct {
    fn new(data: Vec<EntryOwned>) -> LazyStruct {
        Self {
            cache: data,
        }
    }

    fn get_entry(&'a self, index: usize) -> Option<Entry<'a>> {
        match self.cache.get(index) {
            Some(entry_owned) => Some(entry_owned.to_entry()),
            None => None,
        }
    }
}

impl<'a> IntoIterator for &'a mut LazyStruct {
    type Item = Entry<'a>;
    type IntoIter = LazyStructIter<'a>;

    fn into_iter(self) -> Self::IntoIter {
        LazyStructIter {
            inner: self,
            current_index: 0,
        }
    }
}

struct LazyStructIter<'a> {
    inner: &'a mut LazyStruct,
    current_index: usize,
}

impl<'a> LazyStructIter<'a> {
    fn next_item(&'a mut self) -> Option<Entry<'a>> {
        if self.current_index > self.inner.cache.len() {
            return None;
        }
        let ret = self.inner.get_entry(self.current_index);
        self.current_index += 1;
        ret
    }
}

impl<'a> Iterator for LazyStructIter<'a> {
    type Item = Entry<'a>;

    fn next(&mut self) -> Option<Self::Item> {
        self.next_item()
    }
}

Which yields me to a lifetime issue:这让我想到了一个终生的问题:

   Compiling playground v0.0.1 (/playground)
error[E0495]: cannot infer an appropriate lifetime for autoref due to conflicting requirements
  --> src/main.rs:64:14
   |
64 |         self.next_item()
   |              ^^^^^^^^^
   |
note: first, the lifetime cannot outlive the anonymous lifetime #1 defined on the method body at 63:5...
  --> src/main.rs:63:5
   |
63 | /     fn next(&mut self) -> Option<Self::Item> {
64 | |         self.next_item()
65 | |     }
   | |_____^
note: ...so that reference does not outlive borrowed content
  --> src/main.rs:64:9
   |
64 |         self.next_item()
   |         ^^^^
note: but, the lifetime must be valid for the lifetime `'a` as defined on the impl at 60:6...
  --> src/main.rs:60:6
   |
60 | impl<'a> Iterator for LazyStructIter<'a> {
   |      ^^
note: ...so that the types are compatible
  --> src/main.rs:64:14
   |
64 |         self.next_item()
   |              ^^^^^^^^^
   = note: expected  `&mut LazyStructIter<'_>`
              found  `&mut LazyStructIter<'a>`

The lifetime of the references should be bind to the LazyStruct , but I cannot change the Iter trait do not accept any lifetime specifier.引用的生命周期应该绑定到LazyStruct ,但我无法更改 Iter 特征,不接受任何生命周期说明符。 I have already check some answers to similar issues: Iterator returning items by reference, lifetime issue How do I write an iterator that returns references to itself?我已经检查了一些类似问题的答案: Iterator return items by reference,lifetime issue 如何编写一个返回对自身的引用的迭代器?

EDIT : The Entry is a more complex data structure and it is not possible to copy it.编辑Entry是一个更复杂的数据结构,无法复制它。 I have to bind it to a specific lifetime since it contains references to things.我必须将它绑定到特定的生命周期,因为它包含对事物的引用。

One of them points that the iterator should hold a reference to the original collection instead of owning it since it is not allowed to return a reference with the self lifetime.其中之一指出迭代器应该持有对原始集合的引用而不是拥有它,因为它不允许返回具有自身生命周期的引用。 But I could't make it work.但我无法让它工作。 So, how should I play the references here?那么,我应该如何在这里播放参考资料?

Here is the playground example这是操场示例

You can't.你不能。

You require that each item returned by next() has a reference with a lifetime tied to the existence of the LazyStructIter iterator.您要求next()返回的每个项目都有一个引用,其生命周期与LazyStructIter迭代器的存在相关。

This it is not possible with the Iterator interface: Iterator接口无法做到这一点:

pub trait Iterator {
    type Item;
    fn next(&mut self) -> Option<Self::Item>;

But it would be possible with a trait defined as:但是有可能将特征定义为:

trait FakeIterator<'a> {
    type Item;

    fn next(&'a mut self) -> std::option::Option<Self::Item>;
}

impl<'a> FakeIterator<'a> for LazyStructIter<'a> {
    type Item = Entry<'a>;

    fn next(&'a mut self) -> Option<Self::Item> {
        self.next_item()
    }
}

Tha capability to have a kind of iterator which returns items borrowing from self is the goal of RFC 1598 - GAT .拥有一种迭代器来返回从自身借用的项目的能力是RFC 1598-GAT的目标。

See also this article for a collection of workarounds about this topic.另请参阅本文以获取有关此主题的解决方法的集合。

Generally you don't need to specify lifetimes in rust unless 1 of two things is true, the reference is bound to an owner that isn't known, or a reference that is static.通常你不需要在 rust 中指定生命周期,除非两件事中的一件是真的,引用绑定到一个未知的所有者,或者一个静态的引用。 Rust says it expected '_ lifetime, which means it understands the ownership and borrows on its own. Rust 说它期望'_生命周期,这意味着它了解所有权并自行借用。

https://play.rust-lang.org/?version=stable&mode=debug&edition=2018&gist=c54f5f2f24e635dcfaa0fcbf69fa4ce0 https://play.rust-lang.org/?version=stable&mode=debug&edition=2018&gist=c54f5f2f24e635dcfaa0fcbf69fa4ce0

struct EntryOwned(u32);
struct Entry(u32);

impl EntryOwned {
    fn to_entry(&self) -> Entry {
        Entry(self.0)
    }
}

struct LazyStruct {
    cache: Vec<EntryOwned>,
}

impl LazyStruct {
    fn new(data: Vec<EntryOwned>) -> LazyStruct {
        Self {
            cache: data,
        }
    }

    fn get_entry(&self, index: usize) -> Option<Entry> {
        match self.cache.get(index) {
            Some(entry_owned) => Some(entry_owned.to_entry()),
            None => None,
        }
    }
}

impl IntoIterator for LazyStruct {
    type Item = Entry;
    type IntoIter = LazyStructIter;

    fn into_iter(self) -> Self::IntoIter {
        LazyStructIter {
            inner: self,
            current_index: 0,
        }
    }
}

struct LazyStructIter {
    inner: LazyStruct,
    current_index: usize,
}

impl LazyStructIter {
    fn next_item(&mut self) -> Option<Entry> {
        if self.current_index > self.inner.cache.len() {
            return None;
        }
        let ret = self.inner.get_entry(self.current_index);
        self.current_index += 1;
        ret
    }
}

impl Iterator for LazyStructIter {
    type Item = Entry;

    fn next(&mut self) -> Option<Self::Item> {
        self.next_item()
    }
}


fn main() {
    // let json_data = r#"{"item_1" : 10, "item_2" : 100, "item_3" : 1000}"#;
    // if let Ok(data) = serde_json::from_str::<A>(json_data) {
    //     println!("{:?}", data);
    // }
    // else if let Ok(data) = serde_json::from_str::<B>(json_data) {
    //     println!("{:?}", data);
    // }
    for _ in 0..0 {
        println!("foo");    
    }
}

After removing the lifetime specifications, it compiles fine and runs.删除生命周期规范后,它可以正常编译并运行。

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

相关问题 包装返回迭代器的 function 时的生命周期问题 - Lifetime issue when wrapping a function returning an Iterator 实现Iterator时的生命周期问题 - Lifetime issue when implementing Iterator 迭代器通过引用返回项目,生命周期问题 - Iterator returning items by reference, lifetime issue 从迭代器返回切片时无法推断适当的生命周期 - Cannot infer an appropriate lifetime when returning a slice from an iterator 如何在返回新接收的值和缓存值之间的所有组合的迭代器时修复生命周期问题? - How do I fix a lifetime issue when returning an iterator of all combinations between a newly received value and cached values? 方法返回迭代器的生命周期错误 - Lifetime error for method returning iterator 将迭代器映射到矩阵的元素时的生命周期问题 - Lifetime issue when mapping an iterator over elements of a matrix 在递归函数中链接本地迭代器时出现 Rust Lifetime 问题 - Rust Lifetime issue when chaining local iterator in recursive function 在实现返回可变引用的迭代器时,如何解决“无法为 autoref 推断适当的生命周期”? - How can I fix “cannot infer an appropriate lifetime for autoref” when implementing an iterator that returns mutable references? 使用 Any trait 获取对包含引用的结构的引用时的生命周期问题 - Lifetime issue when using the Any trait to get references to structs containing references
 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM