为实现具有关联生命周期的特征的泛型类型实现特征时的生命周期问题

Lifetime issue while implementing a trait for a generic type which implements a trait with an associated lifetime

我正在为一个项目编写反序列化器(Vec<u8>(Raw JSON)到任何类型 T)并尝试为其使用 serde。这是我解码数据的特征:

pub trait Decode: Sized {
    fn try_decode(input: Vec<u8>) -> Result<Self, InternalError>;
}

因为我打算在我的结构上使用 #[derive(Deserialize)],所以我正在为任何实现具有任意生命周期的 Deserialize 特性的类型编写一个 impl:

impl<'a, T: Deserialize<'a>> Decode for T {
    fn try_decode(input: Vec<u8>) -> Result<Self, InternalError> {
        if let Ok(t) = serde_json::from_slice(&input) {
            Ok(t)
        } else {
            Err(Internal::decode("Could not decode"))
        }
    }
}

但我遇到了终身错误:

error[E0597]: `input` does not live long enough
  --> src/decode.rs:16:47
   |
14 | impl<'a, T: Deserialize<'a>> Decode for T {
   |      -- lifetime `'a` defined here
15 |     fn try_decode(input: Vec<u8>) -> Result<Self, InternalError> {
16 |         if let Ok(t) = serde_json::from_slice(&input) {
   |                        -----------------------^^^^^^-
   |                        |                      |
   |                        |                      borrowed value does not live long enough
   |                        argument requires that `input` is borrowed for `'a`
...
21 |     }
   |     - `input` dropped here while still borrowed

我明白为什么编译器生我的气了。在检查 from_slice 的实现后,我认为它有一个相关的生命周期。我确信输入是一个拥有的值,但 from_slice 需要一个引用,所以我在这里返回一个值的引用,该值在函数结束时被删除,这显然是不正确的。我的问题是,有没有办法确保在 <'a> 生命周期内借用该值(即此函数的调用者提供的生命周期)。我无法更新特征,因为它会导致灾难。

使用生命周期反序列化的正确方法是使用 Higher Rank Trait Bounds:使用 for<'a> 表示法明确告诉编译器此生命周期对所有(相关)生命周期有效。代码将如下所示:

impl<T: for<'de> Deserialize<'de>> InputCoercible for T {
    // ...trait methods...
}

如果你想要一个不从切片借用的值,你可以使用 DeserializeOwned 作为特征边界,它没有关联的生命周期(因此只存储拥有的值)。例如,这个编译:

impl<T: DeserializeOwned> Decode for T {
    fn try_decode(input: Vec<u8>) -> Result<Self, InternalError> {
        if let Ok(t) = serde_json::from_slice(&input) {
            Ok(t)
        } else {
            todo!()
        }
    }
}

Playground

这相当于使用较高级别的特征边界和较低级别的 Deserialize 特征边界:

impl<T: for<'de> Deserialize<'de>> Decode for T {
    // ...
}