我想编写处理与事务提交相关的逻辑的函数transactional

fn get_client() -> Client {
    return Client{};
}

struct Client {}

impl Client {
    pub async fn commit(&mut self) -> Result<(), Error> {
        return Ok(());
    }

    pub async fn find_and_update(&mut self) -> Vec<u64> {
        return vec![];
    }
}


pub async fn transactional<F, Fut, R>(action: F) -> Result<R, Error>
where
F: Fn(&mut Client) -> Fut,
Fut: Future<Output = R>
{
    let mut client = get_client();
    loop {
        let action_result = action(&mut client).await;
        if let Err(err) = client.commit().await {
            continue;
        }
        return Ok(action_result);
    }
}

pub async fn make_request() -> Vec<u64> {
    return transactional(
        async move |session| session.find_and_update().await
    ).await.unwrap();
}

#[tokio::main]
async fn main() -> Result<(), io::Error>{
    let r = make_request().await;
    return Ok(())
}

但我得到了以下错误

   |         async move |session| session.find_and_update().await
   |         ^^^^^^^^^^^^--------
   |         |           |      |
   |         |           |      return type of closure `impl futures::Future<Output = Vec<u64>>` contains a lifetime `'2`
   |         |           has type `&'1 mut Client`
   |         returning this value requires that `'1` must outlive `'2`

是否可以指定&amp;客户端的生命周期 比Future长,而两者的生命周期 都比循环迭代短?

有没有可能在不使用指针的情况下修复这个问题?

cargo --version
cargo 1.64.0-nightly (a5e08c470 2022-06-23)

推荐答案

起初,我重写了您的代码,以不使用不稳定的异步闭包.然后您可以看到,在异步块|session| async move {..}中borrow Client只可能用于'static,而您没有它.因此,你需要给它一个拥有的价值.在我的例子中,我将所有权传递给异步块并在结果中返回它.我不确定这是不是一个好的设计,但它是可行的.

use std::future::Future;
use tokio; // 1.19.2

fn get_client() -> Client {
    return Client{};
}

pub struct Client {}

impl Client {
    pub async fn commit(&mut self) -> Result<(), Error> {
        return Ok(());
    }

    pub async fn find_and_update(&mut self) -> Vec<u64> {
        return vec![];
    }
}

pub async fn transactional<F, Fut, R>(action: F) -> Result<R, Error>
where
F: Fn(Client) -> Fut,
Fut: Future<Output = (R, Client)>
{
    let mut client = get_client();
    loop {
        let (action_result, c) = action(client).await;
        client = c;

        if let Err(err) = client.commit().await {
            continue;
        }
        return Ok(action_result);
    }
}

pub async fn make_request() -> Vec<u64> {
    return transactional(|mut session| async move { // move `client` into async, not borrow
        let r = session.find_and_update().await;
        (r, session)
    }).await.unwrap();
}

#[tokio::main]
async fn main() -> Result<(), std::io::Error>{
    let r = make_request().await;
    return Ok(())
}

#[derive(Debug)]
pub struct Error;

Rust相关问答推荐

当为a Self:IntoIterator设置trait bind `时,获取`a T `不是迭代器"&'"<'>&'

当一个箱子有自己的依赖关系时,两个人如何克服S每箱1库+n箱的限制?

为什么reqwest以文本形式下载二进制文件?

在UdpSocket上使用sendto时的隐式套接字绑定

有没有办法避免在While循环中多次borrow `*分支`

在自定义序列化程序中复制serde(With)的行为

如何为rust trait边界指定多种可能性

try 从标准输入获取用户名和密码并删除 \r\n

需要一个有序向量来进行 struct 初始化

Rust 中的生命周期:borrow 的 mut 数据

从嵌入式 Rust 中的某个时刻开始经过的时间

具有在宏扩展中指定的生命周期的枚举变体数据类型

如何获取函数中borrow 的切片的第一部分?

在异步 Rust 中,Future 如何确保它只调用最近的 Waker?

为什么具有 Vec 变体的枚举没有内存开销?

将一片字节复制到一个大小不匹配的数组中

当我不满足特征界限时会发生什么?

我可以在不调用 .clone() 的情况下在类型转换期间重用 struct 字段吗?

制作嵌套迭代器的迭代器

TinyVec 如何与 Vec 大小相同?