我是用actix_web 2.0。 根据官方教程,我使用 serde 解 json。于是有了如下代码:
async fn deserialize_json<'a, T>(mut payload: web::Payload) -> Result<T, Error>
where
T: 'a + serde::Deserialize<'a>,
{
const MAX_SIZE: usize = 262_144; // max payload size is 256k
// payload is a stream of Bytes objects
let mut body:BytesMut= BytesMut::new();
while let Some(chunk) = payload.next().await {
let chunk = chunk?;
// limit max size of in-memory payload
if (body.len() + chunk.len()) > MAX_SIZE {
return Err(error::ErrorBadRequest("overflow"));
}
body.extend_from_slice(&chunk);
}
// body is loaded, now we can deserialize serde-json
let obj = serde_json::from_slice::<T>(&body)?;
Ok(obj)
}
然后编译器报错:body
does not live long enough
具体如下
|
45 | async fn deserialize_json<'a, T>(mut payload: web::Payload) -> Result<T, Error>
| -- lifetime `'a` defined here
...
63 | let obj:T = serde_json::from_slice::<T>(&body)?;
| ----------------------------^^^^^-
| | |
| | borrowed value does not live long enough
| argument requires that `body` is borrowed for `'a`
64 | Ok(obj)
65 | }
| - `body` dropped here while still borrowed
然后,我分析了一波。我把T换成一个确定的结构体,然后编译通过了,并且跑的结果也正确。具体结构体如下:
#[derive(Serialize, Deserialize, Debug)]
pub struct LoginStruct {
username: String,
password: String,
}
然后我就没有思路了,搜了半天生命周期和泛型,毫无头绪。
最后我加了一个参数,从外部传入一个 BytesMut 来做 body 的owner,然而编译器的报错一个字都没变。改后具体代码如下:
async fn deserialize_json<'a, T>(mut payload: web::Payload, buffer: &'a mut BytesMut) -> Result<T, Error>
where
T: serde::Deserialize<'a>,
{
const MAX_SIZE: usize = 262_144; // max payload size is 256k
// payload is a stream of Bytes objects
let mut body = buffer;
while let Some(chunk) = payload.next().await {
let chunk = chunk?;
// limit max size of in-memory payload
if (body.len() + chunk.len()) > MAX_SIZE {
return Err(error::ErrorBadRequest("overflow"));
}
body.extend_from_slice(&chunk);
}
// body is loaded, now we can deserialize serde-json
let obj = serde_json::from_slice::<T>(&body)?;
Ok(obj)
}
请教各位大神,如何才能延长body的生命周期,使函数编译通过?
刚刚开始学rust,谢谢大家
1
共 6 条评论, 1 页
评论区
写评论serde::Deserialize<'de>
带生命周期参数的目的是允许用户实现“零拷贝反序列化”,在这个例子中就是serde_json::from_slice::<T>(&body)
中的T
可以没有自己的数据,所有成员(或者部分成员)都引用body
的内容,这样就使得T
绑定了生命周期。T
的 trait bound 为'a + serde::Deserialize<'a>
的时候,编译器不能确定T
中有没有body
的引用,只能按有对待,所以需要T
的生命周期不超出body
。这就解释了错误提示“argument requires thatbody
is borrowed for'a
”,因为T: 'a
,所以至少需要&'a body
成立,但是obj
是要返回到函数外面的,而body
只能活在函数内部,所以必然不能满足,从而有“body
dropped here while still borrowed”。T
换成所述的结构体后,编译器确定T
是不需要引用body
的(因为成员都是String
),所以不再要求生命周期一致。for<'a > serde::Deserialize<'a>
或者serde::de::DeserializeOwned
作为T
的 trait bound,是明确告知编译器T
不引用body
的内容,所以编译器不会提生命周期的要求。但如果调用该函数的时候使用了引用body
的T
,就会使上述 bound 不满足而无法通过编译。PS.
serde::de::DeserializeOwned
的定义:impl<T> DeserializeOwned for T where T: for<'de> Deserialize<'de>,
感谢!您的方法确实有效
对以下内容的回复:
两种办法,参考serde反序列化的用法。https://serde.rs/lifetimes.html
async fn deserialize_json<T>(mut payload: web::Payload) -> Result<T, Error> where T: for<'a >+ serde::Deserialize<'a>
async fn deserialize_json<T>(mut payload: web::Payload) -> Result<T, Error> where T: serde::de::DeserializeOwned
没编译试过,不过应该可以。
我知道了, 你给T加一个'static试试 对以下内容的回复:
为什麽把 T 换成 LoginStruct 就通过编译了呢?
对以下内容的回复:
你这里,, aysnc不是立马执行的, async的结果可能还会跨线程,不要把 &mut buffer传进来, 用let body = BytesMut::new(), 要传的话..最简单的用Arc<Muxtex<>>