在 FromForm 中反序列化 JSON 时的生命周期

Lifetimes when Deserializing JSON within a FromForm

我无法理解这段代码的生命周期之间的关系。基本上,我有一个 Rocket API 接收一些 x-www-form-urlencoded 数据,只有一个键:json。直觉上,这个键包含一个 JSON 值,用百分比编码编码,结构 Message<T>.

(我知道这是次优的 API 设计,但这是逆向工程工作,所以我别无选择)

为了像 From<Message<T>> 一样轻松用作请求守卫,我正在实施 FromForm。为此,我需要为 T 实现 Deserialize<'de> 的任何 Message<T> 实现 FromForm<'f>。我将我的 impl 签名写为 impl<'f, 'de, T> FromForm<'f> for Message<T> where T: Deserialize<'de>.

为了实际执行解码,我:

  1. 获取表单数据的"json"键;
  2. URL-解码值;
  3. 解析值中包含的JSON。

尽快摆脱困境。执行此操作的代码(为了 reader 的方便而进行的显式类型注释):

fn from_form(items: &mut FormItems<'f>, strict: bool) -> Result<Self, Self::Error> {
    // Get JSON field
    let encoded: Option<&RawStr> = items.find(|&(k, _)| k.as_str() == "json")
        .map(|(_, v)| v);
    if let None = encoded {
        return Err(MessageFormError::MissingJsonKey);
    }

    // Decode URL-string
    let decoded: Result<String, Utf8Error> = encoded.unwrap().url_decode();
    if let Err(e) = decoded {
        return Err(MessageFormError::InvalidUrl(e));
    }

    // Parse JSON
    let json: String = decoded.unwrap();
    serde_json::from_str::<Self>(&json) // Line 205
        .map_err(|e| MessageFormError::InvalidJson(e))
}

A Gist demonstrating the problem 以粘贴和运行 的方式(在 Playground 上不起作用,因为它依赖于 Rocket)。

据我了解:

不过我的理解好像有误:

205 |         serde_json::from_str::<Self>(&json)
    |                                       ^^^^ does not live long enough
206 |             .map_err(|e| MessageFormError::InvalidJson(e))
207 |     }
    |     - borrowed value only lives until here
    |
note: borrowed value must be valid for the lifetime 'f as defined on the impl at 184:1...
   --> src/transport.rs:184:1
    |
184 | / impl<'f, T> FromForm<'f> for Message<T>
185 | |     where T: Deserialize<'f>
186 | | {
187 | |     type Error = MessageFormError;
...   |
207 | |     }
208 | | }
    | |_^

我哪里出错了,我怎样才能 return 正确地反序列化值?

This section of the Serde website covers Deserialize bounds in detail.


There are two main ways to write Deserialize trait bounds, whether on an impl block or a function or anywhere else.

  • <'de, T> where T: Deserialize<'de>

    This means "T can be deserialized from some lifetime." The caller gets to decide what lifetime that is. Typically this is used when the caller also provides the data that is being deserialized from, for example in a function like serde_json::from_str. In that case the input data must also have lifetime 'de, for example it could be &'de str.

  • <T> where T: DeserializeOwned

    This means "T can be deserialized from any lifetime." The callee gets to decide what lifetime. Usually this is because the data that is being deserialized from is going to be thrown away before the function returns, so T must not be allowed to borrow from it. In your case the data is coming from URL-decoding some input, and the decoded data is thrown away after deserializing T. Another common use of this bound is functions that deserialize from an IO stream, such as serde_json::from_reader.

    To say it more technically, the DeserializeOwned trait is equivalent to the higher-rank trait bound for<'de> Deserialize<'de>. The only difference is DeserializeOwned is more intuitive to read. It means T owns all the data that gets deserialized.

T: DeserializeOwned 替换你的 T: Deserialize<'f> 正确传达不允许 T 从 URL-解码数据,因为URL-解码数据不会比 T.

存在时间更长