3

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

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

为了方便地用作请求保护From<Message<T>>,我正在实施FromForm. 为此,我需要FromForm<'f>为任何Message<T>地方T实现 implements Deserialize<'de>。我将我的 impl 签名写为impl<'f, 'de, T> FromForm<'f> for Message<T> where T: Deserialize<'de>.

要实际执行解码,我:

  1. 获取"json"表单数据的key;
  2. URL解码值;
  3. 解析值中包含的 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))
}

以粘贴运行方式演示问题的要点(不适用于 Playground,因为它依赖于 Rocket)。

我认为:

  • &RawStrencoded一生'f
  • AString是由它创建的url_decode,它一直存在到函数结束
  • serde_json接受一个不需要与 重合的&'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 | | }
    | |_^

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

4

1 回答 1

8

Serde 网站的这一部分Deserialize详细介绍了边界。


有两种主要的方法来编写Deserializetrait bound,无论是在 impl 块或函数上还是在其他任何地方。

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

    这意味着“T 可以从某个生命周期中反序列化”。调用者可以决定那是什么生命周期。通常,当调用者还提供要反序列化的数据时使用,例如在类似 serde_json::from_str. 在这种情况下,输入数据也必须具有生命周期'de,例如它可以是&'de str.

  • <T> where T: DeserializeOwned

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

    说得更专业一点,DeserializeOwned trait 相当于更高级别的 trait bound for<'de> Deserialize<'de>。唯一的区别是DeserializeOwned阅读起来更直观。这意味着 T 拥有所有被反序列化的数据。

T: Deserialize<'f>绑定替换为T: DeserializeOwned 正确表示不允许 T 从 URL 解码的数据中借用,因为 URL 解码的数据不会比 T 更有效。

于 2017-08-20T15:42:31.453 回答