关联类型的生命周期绑定被拒绝,尽管它看起来有效

lifetime bound on associated type is rejected although it seems valid

我有一段代码无法编译,可以简化为这个片段:

use std::error::Error;
use std::convert::TryFrom;

// A trait that provides methods for parsing data into a type T.
pub trait Deserializable<T> {
    // some methods
}

pub struct MyBuffer<'a> {
    inner: &'a [u8]
}

impl<'a, T> Deserializable<T> for MyBuffer<'a> 
where
    T: TryFrom<&'a [u8]>,
    <T as TryFrom<&'a [u8]>>::Error: Error + Sync + Send + 'static 
{
    // some methods to implement
}

fn main() {}

编译器拒绝此程序并显示令人困惑的错误消息:

error[E0310]: the associated type `<T as std::convert::TryFrom<&[u8]>>::Error` may not live long enough
  --> src/main.rs:13:13
   |
13 | impl<'a, T> Deserializable<T> for MyBuffer<'a> 
   |             ^^^^^^^^^^^^^^^^^
   |
   = help: consider adding an explicit lifetime bound `<T as std::convert::TryFrom<&[u8]>>::Error: 'static`...
note: ...so that the type `<T as std::convert::TryFrom<&[u8]>>::Error` will meet its required lifetime bounds
  --> src/main.rs:13:13
   |
13 | impl<'a, T> Deserializable<T> for MyBuffer<'a> 
   |             ^^^^^^^^^^^^^^^^^

错误提示我添加 'static lifetime bound,但我已经添加了它:

consider adding an explicit lifetime bound `<T as std::convert::TryFrom<&[u8]>>::Error: 'static`

有人可以解释为什么这个程序不能编译,and/or如何修复它(如果可能)?在我看来,应该 可以让 <T as TryFrom<&'a [u8]>>::Error 成为 'static,即使 T 本身绑定到 'a

我希望 Error 成为 'static 的原因是我使用 failure 并且 failure::Fail 是为 Send + Sync + Error + 'static 实现的。

我仍然不确定为什么,但似乎只是删除错误的静态绑定?

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

这似乎是编译器推断生命周期和相关类型的能力的一个差距。

有时,为了帮助编译器,您可以添加泛型参数来为关联类型添加别名。这个参数不是 "count" 因为它不会使项目 "more generic",但是因为泛型是在使用而不是声明时解析的,所以它推迟了类型检查的困难部分,直到知道确切的类型.换句话说:编译器可能能够证明任何 particular T::Error 有效,但它不能完全证明 every T::Error 必须工作,所以我们引入一个新参数 E ,它必然是 T::Error 并告诉编译器只有在我们尝试使用它时才弄清楚 E 是什么.

以下作品(playground):

impl<'a, T, E> Deserializable<T> for MyBuffer<'a>
where
    T: TryFrom<&'a [u8], Error = E>,
    E: Error + Sync + Send + 'static,
{
    // ...
}

我们引入了一个新的类型参数E,而不是边界T::Error,并限制T,使其TryFrom::ErrorE.这在逻辑上(据我所知)与你写的是一样的,但它编译时没有抱怨。

我找不到相关的官方文档;它可能是求解器的固有限制,或者仅仅是一个错误。