在 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
的 &RawStr
具有生命周期 'f
。
String
是由 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 | |
| |_^
我做错了什么,如何正确返回反序列化的值?
【问题讨论】:
能不能把代码放在playground里,方便转载?乍一看,'f
和 'de
的生命周期之间似乎存在缺失关系。
@E_net4 不完全是,因为操场上没有 Rocket 板条箱,很遗憾。我会做一个更完整的例子,可以粘贴到文件中。
@E_net4 添加了要点!
【参考方案1】:
This section of the Serde website covers Deserialize
bounds in detail.
Deserialize
trait bounds 有两种主要的写法,无论是 在 impl 块或函数或其他任何地方。
<'de, T> where T: Deserialize<'de>
这意味着“T 可以从 some 生命周期中反序列化。”调用者可以决定那是什么生命周期。通常这是使用 当调用者还提供正在反序列化的数据时 来自,例如在一个函数中
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 boundfor<'de> Deserialize<'de>
。唯一不同的是DeserializeOwned
更多 直观的阅读。这意味着 T 拥有所有获得的数据 反序列化。
用T: DeserializeOwned
替换绑定的T: Deserialize<'f>
正确传达 T 不允许从
URL 解码的数据,因为 URL 解码的数据不会超过 T。
【讨论】:
啊,现在我明白了。输入必须比输出长是有道理的,我没有意识到生命周期是如何仅从参考连接的。但我必须同意 Shepmaster 的观点,请内联回答问题。以上是关于在 FromForm 中反序列化 JSON 时的生命周期的主要内容,如果未能解决你的问题,请参考以下文章