在 FromForm 中反序列化 JSON 时的生命周期
Lifetimes when Deserializing JSON within a FromForm
我无法理解这段代码的生命周期之间的关系。基本上,我有一个 Rocket API 接收一些 x-www-form-urlencoded
数据,只有一个键:json
。直觉上,这个键包含一个 JSON 值,用百分比编码编码,结构 Message<T>
.
(我知道这是次优的 API 设计,但这是逆向工程工作,所以我别无选择)
为了像 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>
.
为了实际执行解码,我:
- 获取表单数据的
"json"
键;
- URL-解码值;
- 解析值中包含的JSON。
尽快摆脱困境。执行此操作的代码(为了 reader 的方便而进行的显式类型注释):
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
重合,return 是一个值(所以它一直存在到最后函数的一部分,并且因为它是 returned,所以被移到了它之外)
不过我的理解好像有误:
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 | | }
| |_^
我哪里出错了,我怎样才能 return 正确地反序列化值?
This section of the Serde website covers Deserialize
bounds in detail.
There are two main ways to write Deserialize
trait bounds, whether
on an impl block or a function or anywhere else.
<'de, T> where T: Deserialize<'de>
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
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
.
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.
存在时间更长
我无法理解这段代码的生命周期之间的关系。基本上,我有一个 Rocket API 接收一些 x-www-form-urlencoded
数据,只有一个键:json
。直觉上,这个键包含一个 JSON 值,用百分比编码编码,结构 Message<T>
.
(我知道这是次优的 API 设计,但这是逆向工程工作,所以我别无选择)
为了像 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>
.
为了实际执行解码,我:
- 获取表单数据的
"json"
键; - URL-解码值;
- 解析值中包含的JSON。
尽快摆脱困境。执行此操作的代码(为了 reader 的方便而进行的显式类型注释):
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
重合,return 是一个值(所以它一直存在到最后函数的一部分,并且因为它是 returned,所以被移到了它之外)
不过我的理解好像有误:
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 | | }
| |_^
我哪里出错了,我怎样才能 return 正确地反序列化值?
This section of the Serde website covers Deserialize
bounds in detail.
There are two main ways to write
Deserialize
trait bounds, whether on an impl block or a function or anywhere else.
<'de, T> where T: Deserialize<'de>
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
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
.To say it more technically, the
DeserializeOwned
trait is equivalent to the higher-rank trait boundfor<'de> Deserialize<'de>
. The only difference isDeserializeOwned
is more intuitive to read. It means T owns all the data that gets deserialized.
用 T: DeserializeOwned
替换你的 T: Deserialize<'f>
正确传达不允许 T 从
URL-解码数据,因为URL-解码数据不会比 T.