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

时间:2017-08-20 14:41:40

标签: rust serde rust-rocket

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

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

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

要实际执行解码,我:

  1. 获取表单数据的"json"键;
  2. 对值进行URL解码;
  3. 解析值中包含的JSON。
  4. 尽快纾困。代码这样做(显式类型注释为读者带来方便):

    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(因为它依赖于Rocket而不能在Playground上运行)。

    据我所知:

    • &RawStr encoded的有效期为'f
    • Stringurl_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 | | } | |_^ 重合,并返回一个值(因此它会一直存在到函数的末尾,因此它被退回了,超越了它)

    但似乎我的理解不正确:

    // Large devices (desktops, less than 1200px)
     @media (max-width: 1199px) { ... }
    
     // Medium devices (tablets, less than 992px)
     @media (max-width: 991px) { ... }
    
     // Small devices (landscape phones, less than 768px)
     @media (max-width: 767px) { ... }
    
     // Extra small devices (portrait phones, less than 576px)
     @media (max-width: 575px) { ... }
    

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

1 个答案:

答案 0 :(得分:2)

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

  

有两种主要方式来编写Deserialize特征边界,无论如何   在impl块或函数或其他任何地方。

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

         

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

  •   
  • <强> <T> where T: DeserializeOwned

         

    这意味着“T可以从任何生命周期中反序列化。”被调用者可以决定生命周期。通常这是因为数据   正被反序列化的内容将在之前被抛弃   函数返回,所以不能允许T从中借用。 在你的   如果数据来自URL解码某些输入,则解码   反序列化T后数据被丢弃。这是另一种常见用法   bound是从IO流反序列化的函数,例如   serde_json::from_reader

         

    从技术角度来说,DeserializeOwned   特质相当于higher-rank trait bound   for<'de> Deserialize<'de>。唯一的区别是DeserializeOwned更多   直观易读。这意味着T拥有所有获得的数据   反序列化。

  •   

T: Deserialize<'f>替换T: DeserializeOwned绑定 正确地告知T不允许从中借用 URL解码数据,因为URL解码数据不会比T更长。