最初的写法与报错
关键报错信息:
error: lifetime may not live long enough
returning this value requires that'life0
must outlive'static
这是一个看起来很好解决的生命周期错误
其实也就是生命周期结合闭包和异步的问题
介绍:
为了实现失效缓存,写了一个包装redis操作的函数,在参数里接收闭包
但在使用的时候发现问题还是存在的
问题似乎与闭包和生命周期相关
于是按照错误输出的提示进行几次修改
并最终修改完成 不再报错
// 最初的代码片断
async fn delete_by_id(&self, id: &str) -> Result<(), MyErr> {
// 这里是要失效的redisKey 可能不止一个所以使用vec
let cache_keys = vec![];
// 调用redis包装方法 传入redis连接 和业务逻辑闭包
redisutil::cache_wrap::invalid_cache_keys(self.redis.clone(), cache_keys, || Box::pin(async move {
// 业务逻辑处理代码 调用关系数据库封装方法完成删除动作
let res = Dao::delete_by_id(&self.db.clone(), id).await?;
Ok(res)
})).await
}
由报错信息推断是闭包捕获了self的引用
而引起生命周期问题
&self的生命必须和’static一样长或长与’static
这是不可能的事 肯定是那里有问题
error: lifetime may not live long enough
--> service\maitian\user\src\svc.rs:38:13
|
35 | async fn delete_by_id(&self, id: &str) -> Result<(), MyErr> {
| - lifetime `'life0` defined here
...
38 | / Box::pin(async move {
39 | | let res = Dao::delete_by_id(&self.db.clone(), id).await?;
40 | | Ok(res)
41 | | })
| |______________^ returning this value requires that `'life0` must outlive `'static`
第一次修改 改成这样之后报不能移动的错误
把db和id单独拉出来试试
async fn delete_by_id(&self, id: &str) -> Result<(), MyErr> {
let cache_keys = vec![];
let db = self.db.clone(); // 单独拉出来的db
let id = id.to_owned(); // 单独拉出来的id
redisutil::cache_wrap::invalid_cache_keys(self.redis.clone(), cache_keys, || Box::pin(async move {
let res = Dao::delete_by_id(&db, &*id).await?;
Ok(res)
})).await
}
报错信息变了
db存活的时间不够长
闭包只捕获了db的引用
db本身并没有转移到闭包里
error[E0507]: cannot move out of `db`, a captured variable in an `Fn` closure
--> service\maitian\user\src\svc.rs:41:22
|
37 | let db = self.db.clone();
| -- captured outer variable
38 | let id = id.to_owned();
39 | redisutil::cache_wrap::invalid_cache_keys(self.redis.clone(), cache_keys, || {
| -- captured by this `Fn` closure
40 |
41 | Box::pin(async move {
| ______________________^
42 | | let res = Dao::delete_by_id(&db, &*id).await?;
| | --
| | |
| | variable moved due to use in generator
| | move occurs because `db` has type `sqlx::Pool<MySql>`, which does not implement the `Copy` trait
43 | | Ok(res)
44 | | })
| |_____________^ `db` is moved here
第二次修改
似乎修改的方向是对的 self不报错了 只有id报错
现在只剩下id的问题了
async fn delete_by_id(&self, id: &str) -> Result<(), MyErr> {
let cache_keys = vec![];
redisutil::cache_wrap::invalid_cache_keys(self.redis.clone(), cache_keys, || {
// 在还没有进入异步的地方把db克隆出来
// 最终返回的future不再引用self
let db = self.db.clone();
// 返回future
Box::pin(async move {
let res = Dao::delete_by_id(&db, id).await?;
Ok(res)
})
}).await
}
error: lifetime may not live long enough
--> service\maitian\user\src\svc.rs:39:13
|
35 | async fn delete_by_id(&self, id: &str) -> Result<(), MyErr> {
| - lifetime `'life1` defined here
...
39 | / Box::pin(async move {
40 | | let res = Dao::delete_by_id(&db, id).await?;
41 | | Ok(res)
42 | | })
| |______________^ returning this value requires that `'life1` must outlive `'static`
最后 没有错误的写法 正确的改法
async fn delete_by_id(&self, id: &str) -> Result<(), MyErr> {
let cache_keys = vec![];
redisutil::cache_wrap::invalid_cache_keys(self.redis.clone(), cache_keys, || {
let db = self.db.clone(); // db
let id = id.to_owned(); // id
// db与id保留在当前闭包里
// 最终返回的future里不再引用self
Box::pin(async move {
Ok(Dao::delete_by_id(&db, &*id).await?)
})
}).await
}