fn do_it<T> (param: T) where for<'de> T: serde::Deserialize<'de> {}
文档用的闭包举例。
https://doc.rust-lang.org/nomicon/hrtb.html
This job requires The Magic of Higher-Rank Trait Bounds (HRTBs). The way we desugar this is as follows:
where for<'a> F: Fn(&'a (u8, u16)) -> &'a u8,
(Where Fn(a, b, c) -> d
is itself just sugar for the unstable real Fn
trait)
for<'a>
can be read as “for all choices of 'a
”, and basically produces an infinite list of trait bounds that F must satisfy. Intense. There aren’t many places outside of the Fn traits where we encounter HRTBs, and even for those we have a nice magic sugar for the common cases.
Tags:actix_web,serde,lifetime
我是用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,谢谢大家
serde::Deserialize<'de>
带生命周期参数的目的是允许用户实现“零拷贝反序列化”,在这个例子中就是 serde_json::from_slice::<T>(&body)
中的 T 可以没有自己的数据,所有成员(或者部分成员)都引用 body 的内容,这样就使得 T 绑定了生命周期。'a + serde::Deserialize<'a>
的时候,编译器不能确定 T 中有没有 body 的引用,只能按有对待,所以需要 T 的生命周期不超出 body。这就解释了错误提示“argument requires that body is borrowed for ’a”,因为 T: 'a
,所以至少需要 &'a body
成立,但是 obj 是要返回到函数外面的,而 body 只能活在函数内部,所以必然不能满足,从而有“body dropped here while still borrowed”。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<>>
原文链接:https://rustcc.cn/article?id=03fbdc76-ebcd-45a9-9843-b43264b03dfd