本文介绍了在FromForm中反序列化JSON的生命周期的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我在理解这段代码的生命周期之间的关系时遇到了麻烦.基本上,我有一个Rocket API,它仅使用一个键即可接收某些x-www-form-urlencoded数据:json.直观地,此键包含结构Message<T>的JSON值(以百分比编码方式编码).

I'm having trouble understanding the relationship between the lifetimes on this code. Basically, I have a Rocket API that receives some x-www-form-urlencoded data, with only one key: json. This key contains, intuitively, a JSON value, encoded with percent-encoding, of a struct Message<T>.

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

(I'm aware this is suboptimal API design, but this is reverse-engineering work, so I have no option)

为了易于用作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>.

To be easily used as a request guard as From<Message<T>>, I'm implementing FromForm. To do that, I need to implement FromForm<'f> for any Message<T> where T implements Deserialize<'de>. I wrote my impl signature as impl<'f, 'de, T> FromForm<'f> for Message<T> where T: Deserialize<'de>.

要实际执行解码,我:

  1. 获取表单数据的"json"键;
  2. URL解码值;
  3. 解析值中包含的JSON.
  1. Get the "json" key of the form data;
  2. URL-decode the value;
  3. Parse the JSON contained in the value.

尽快救助.这样做的代码(为方便读者使用显式类型注释):

Bailing out as soon as possible. Code doing that (explicit type annotations for the reader's convenience):

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

展示问题的Gist (粘贴并运行)(不会在操场上工作,因为它取决于火箭).

A Gist demonstrating the problem in a paste-and-run way (doesn't work on the Playground since it depends on Rocket).

据我了解:

  • encoded&RawStr具有生存期'f.
  • url_decode由它创建一个String,该生存期一直到函数结束
  • serde_json取一个&'x str,其中'x不必与'de一致,然后返回一个值(因此它一直存在于函数的末尾,并且由于返回了它,因此被移到了它的后面).
  • The &RawStr of encoded has lifetime 'f.
  • A String is created out of it by url_decode, which lives until the end of the function
  • serde_json takes a &'x str where 'x does not need to coincide with 'de, and returns a value (so it lives to the end of the function, and since it's returned, gets moved beyond it)

但是看来我的理解是不正确的:

But it seems my understanding is incorrect:

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

我出了什么问题?如何正确返回反序列化的值?

What am I getting wrong, and how can I return the deserialized value properly?

推荐答案

本节Serde网站的详细信息涵盖了Deserialize范围.

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

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

这意味着可以从 some 生命周期开始反序列化T".呼叫者可以决定那是什么寿命.通常使用 当调用方还提供要反序列化的数据时 来自,例如在类似 serde_json::from_str . 在这种情况下,输入数据还必须具有生存期'de,例如 可能是&'de str.

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

<T> where T: DeserializeOwned

这意味着可以从任何生命周期开始反序列化T."被叫方可以决定寿命.通常这是因为数据 被反序列化的将在 函数返回,因此不允许T向其借用. 在您的 如果数据来自URL解码某些输入,然后解码 反序列化T之后,数据就会被丢弃. 绑定是从IO流反序列化的函数,例如 serde_json::from_reader .

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.

从技术上讲, DeserializeOwned 特质等同于高级特质 绑定 for<'de> Deserialize<'de>.唯一的不同是DeserializeOwned更大 直观阅读.这意味着T拥有所有获取的数据 反序列化.

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.

Replacing your T: Deserialize<'f> bound with T: DeserializeOwnedcorrectly communicates that T is not allowed to borrow from theURL-decoded data because the URL-decoded data will not outlive T.

这篇关于在FromForm中反序列化JSON的生命周期的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持!

09-02 11:19