当 &self 拥有与结构体不同的生命周期时

4
在这个例子中
use std::marker::PhantomData;

pub struct A<'a, T> {
    elements: Vec<B<'a, T>>
}

pub struct B<'a, T> {
    _phantom: PhantomData<&'a T>
}

impl<'a, T> A<'a, T> {
    pub fn iter(& self) -> Iter<'a, T> {
        Iter {
            iter: self.elements.iter(),
        }
    }
}

pub struct Iter<'a, T> {
    iter: std::slice::Iter<'a, B<'a, T>>,
}

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

我得到

error[E0495]: cannot infer an appropriate lifetime for lifetime parameter in function call due to conflicting requirements
  --> src/lib.rs:14:24
   |
14 |             iter: self.elements.iter(),
   |                                 ^^^^
   |
note: first, the lifetime cannot outlive the anonymous lifetime defined here...
  --> src/lib.rs:12:17
//...

我知道为什么会发生这种情况:在self.elements中的elements&self有相同的生命周期,因此它不可能创建一个具有生命周期aIter。简单的解决方案是进行以下操作:
pub fn iter(&'a self) -> Iter<'a, T> {
    Iter {
        iter: self.elements.iter(),
    }
}

但是我被迫借用&self来维持其整个生命周期,这会导致其他问题。有什么最简单的解决方案吗?


“但是在代码中,B 对于 'a 是协变的,所以编译器可以将生命周期缩短到仅在需要时而不是整个存在期间,因此我被迫借用 &self 的整个存在期并不完全正确。” - kmdreko
@kmdreko 很不错!我认为在我的更难的例子中,它是不变的。不幸的是,在转换成MVP之前,我总是会忘记某些方面。 - Rafaelo
1个回答

8
你的Iter实现受到过度约束; 你有两个无关的生命周期需要相同。你应该将它们分离:
impl<'a, T> A<'a, T> {
    pub fn iter(&self) -> Iter<'a, '_, T> {
        Iter {
            iter: self.elements.iter(),
        }
    }
}

pub struct Iter<'a, 'b, T> {
    iter: std::slice::Iter<'b, B<'a, T>>,
}

这样,即使'a是不变的,也不会出现将生命周期链接到self的问题。在playground上查看其工作情况(附有额外的测试)。


网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接