使用带有生命周期参数的trait相关联类型时出现了生命周期错误

7

由于使用关联类型,在Rust 1.14中我遇到了终身错误,以下是两个类似的程序,第一个程序可以编译通过而第二个程序则出现了终身错误。

程序 #1 — 编译通过

trait Trait<'a> {
    type T;
}

struct Impl;

impl<'a> Trait<'a> for Impl {
    type T = std::marker::PhantomData<&'a ()>;
}

struct Alpha<'a, T: Trait<'a>> {
    _dummy: std::marker::PhantomData<(&'a (), T)>,
}

fn use_alpha<'a>(_: &'a Alpha<'a, Impl>) {}

fn main() {
    for x in Vec::<Alpha<Impl>>::new().into_iter() {
        use_alpha(&x); // <-- ok
    }
}

程序 #2 — 寿命错误

trait Trait<'a> {
    type T;
}

struct Impl;

impl<'a> Trait<'a> for Impl {
    type T = std::marker::PhantomData<&'a ()>;
}

struct Alpha<'a, T: Trait<'a>> {
    _dummy: std::marker::PhantomData<(&'a (), T::T)>,
}

fn use_alpha<'a>(_: &'a Alpha<'a, Impl>) {}

fn main() {
    for x in Vec::<Alpha<Impl>>::new().into_iter() {
        use_alpha(&x); // <-- !error!
    }
}

以下是第二个程序的编译时错误:

error: `x` does not live long enough
  --> src/main.rs:20:5
   |
19 |         use_alpha(&x); // <-- !error!
   |                    - borrow occurs here
20 |     }
   |     ^ `x` dropped here while still borrowed
   |
   = note: values in a scope are dropped in the opposite order they are created

以下是这两个程序的差异:

 #[derive(Clone)]
 struct Alpha<'a, T: Trait<'a>> {
-    _dummy: std::marker::PhantomData<(&'a (), T)>,
+    _dummy: std::marker::PhantomData<(&'a (), T::T)>,
 }

唯一的区别在于,通过将第一个程序中的类型参数替换为struct定义中的关联类型,会产生生命周期错误。我不知道这为什么会发生。据我所知,关联类型不应该带来任何额外的生命周期限制——它们都只是'a,但很明显Rust编译器持不同意见。
如果我在第二个程序的main函数中用简单的实例化代替迭代,则生命周期错误消失了。也就是说:
fn main() {
    let x = Alpha::<Impl> { _dummy: std::marker::PhantomData };
    use_alpha(&x); // <-- ok in both programs
}

我不明白为什么迭代和直接实例化有什么区别。


我仍在努力解决这个问题。但是我发现你可以使用iter()而不是into_iter(),它会起作用。 - Peter Hall
1个回答

5
use_alpha 函数中,你使用了相同的生命周期来引用 Alpha 和它的生命周期参数。然后,它的生命周期参数变成了 ImplTrait::T 的生命周期。该注释提供了关于值被丢弃的顺序的提示:由于 Impl::TImpl 定义的一部分,所以它会在 Impl 之前被丢弃,但这意味着当它还存在时,Alpha 的某些部分已经被丢弃了。
你可以通过在 use_alpha 中使用两个生命周期参数来解决这个问题:
fn use_alpha<'a, 'b>(_: &'a Alpha<'b, Impl>) {}

这将允许编译器为每种类型推断不同的生命周期。

谢谢你的回答!然而,如果不对我的应用程序进行一些(可能是严重的)重新设计,我需要这两个生命周期保持相同。我通过将“use_alpha”函数的实现复制到调用站点来解决了这个问题。希望我能想出更好的解决方案。 - Craig M. Brandenburg

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