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

Posted

技术标签:

【中文标题】在 FromForm 中反序列化 JSON 时的生命周期【英文标题】:Lifetimes when Deserializing JSON within a FromForm 【发布时间】:2018-01-28 17:08:34 【问题描述】:

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

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

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

要实际执行解码,我:

    获取表单数据的"json"键; 对值进行 URL 解码; 解析值中包含的 JSON。

尽快退出。执行此操作的代码(为方便读者使用显式类型注释):

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)。

据我了解:

encoded&amp;RawStr 具有生命周期 'fString 是由 url_decode 用它创建的,它一直存在到函数结束 serde_json 接受&amp;'x str,其中'x 不需要与'de 重合,并返回一个值(因此它一直存在到函数的末尾,并且由于它被返回,因此被移到它之外)

但看来我的理解是错误的:

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 | | 
    | |_^

我做错了什么,如何正确返回反序列化的值?

【问题讨论】:

能不能把代码放在playground里,方便转载?乍一看,'f'de 的生命周期之间似乎存在缺失关系。 @E_net4 不完全是,因为操场上没有 Rocket 板条箱,很遗憾。我会做一个更完整的例子,可以粘贴到文件中。 @E_net4 添加了要点! 【参考方案1】:

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


Deserialize trait bounds 有两种主要的写法,无论是 在 impl 块或函数或其他任何地方。

&lt;'de, T&gt; where T: Deserialize&lt;'de&gt;

这意味着“T 可以从 some 生命周期中反序列化。”调用者可以决定那是什么生命周期。通常这是使用 当调用者还提供正在反序列化的数据时 来自,例如在一个函数中 serde_json::from_str。 在这种情况下,输入数据还必须具有生命周期'de,例如 可能是&amp;'de str

&lt;T&gt; where T: DeserializeOwned

这意味着“T 可以从任何生命周期中反序列化。”被调用者可以决定什么生命周期。通常这是因为数据 被反序列化的将在 函数返回,所以不能允许 T 借用它。 在您的 如果数据来自对某些输入进行 URL 解码,并且解码后的 反序列化 T 后数据被丢弃。另一个常见的用法 bound 是从 IO 流反序列化的函数,例如 serde_json::from_reader.

更专业地说,DeserializeOwned 特征等同于higher-rank trait bound for&lt;'de&gt; Deserialize&lt;'de&gt;。唯一不同的是DeserializeOwned更多 直观的阅读。这意味着 T 拥有所有获得的数据 反序列化。

T: DeserializeOwned 替换绑定的T: Deserialize&lt;'f&gt; 正确传达 T 不允许从 URL 解码的数据,因为 URL 解码的数据不会超过 T。

【讨论】:

啊,现在我明白了。输入必须比输出长是有道理的,我没有意识到生命周期是如何仅从参考连接的。但我必须同意 Shepmaster 的观点,请内联回答问题。

以上是关于在 FromForm 中反序列化 JSON 时的生命周期的主要内容,如果未能解决你的问题,请参考以下文章

在 Flutter 中反序列化 JSON 数据

在javascript中反序列化json对象

在 Objective C 中反序列化 JSON 字符串

在 Visual Studio 中反序列化 JSON 文件时出错

在 C# 中序列化为 JSON 并在 TS 中反序列化

使用 Newtonsoft Json 从流中反序列化多个 json 对象