通用函数和async_trait的困难。

问题描述 投票:0回答:1

我正试图实现以下特征。

#[async_trait]
pub trait ConnectionPoolTrait<'a: 'b, 'b, T: Client<'a, 'b>>: Clone + Send + Sync {
    type T;
    async fn client(&'a self) -> Result<Self::T>;
    async fn migrate(&self, path: &str) -> Result<()>;
}

当我试图编译代码时,我得到了以下错误。

error[E0495]: cannot infer an appropriate lifetime for lifetime parameter `'b` due to conflicting requirements
  --> src/connection_pool.rs:53:14
   |
53 |       async fn client(&'a self) -> Result<Self::T> {
   |  ______________^
54 | |         Ok(client::Client::new(self.pool.get().await?))
55 | |     }
   | |_____^
   |
note: first, the lifetime cannot outlive the lifetime `'b` as defined on the impl at 51:14...
  --> src/connection_pool.rs:51:14
   |
51 | impl<'a: 'b, 'b, T: Client<'a, 'b>> ConnectionPoolTrait<'a, 'b, T> for ConnectionPool {
   |              ^^
note: ...so that the types are compatible
  --> src/connection_pool.rs:53:14
   |
53 |       async fn client(&'a self) -> Result<Self::T> {
   |  ______________^
54 | |         Ok(client::Client::new(self.pool.get().await?))
55 | |     }
   | |_____^
   = note: expected  `client::ClientTrait<'_, '_>`
              found  `client::ClientTrait<'a, 'b>`
note: but, the lifetime must be valid for the lifetime `'async_trait` as defined on the method body at 50:1...
  --> src/connection_pool.rs:50:1
   |
50 | #[async_trait]
   | ^^^^^^^^^^^^^^
note: ...so that the expression is assignable
  --> src/connection_pool.rs:53:50
   |
53 |       async fn client(&'a self) -> Result<Self::T> {
   |  __________________________________________________^
54 | |         Ok(client::Client::new(self.pool.get().await?))
55 | |     }
   | |_____^
   = note: expected  `std::pin::Pin<std::boxed::Box<(dyn std::future::Future<Output = std::result::Result<client::Client<'_>, Error>> + std::marker::Send + 'async_trait)>>`
              found  `std::pin::Pin<std::boxed::Box<dyn std::future::Future<Output = std::result::Result<client::Client<'_>, Error>> + std::marker::Send>>`
   = note: this error originates in an attribute macro (in Nightly builds, run with -Z macro-backtrace for more info)

这看起来像是与async_trait的冲突问题,但我对如何解决这个问题有点困惑。我的动机是为我的数据库连接创建一个可模拟的接口。我发现一个论坛说这可能是一个编译器的bug 此处希望不是这样。

以下是完整的文件代码

use crate::{client, configuration, Configuration, Pool, Result, Client};
use async_trait::async_trait;
use std::{
    fs,
    marker::{Send, Sync},
};

const SQL_EXTENSION: &str = "sql";

#[derive(Clone)]
pub struct ConnectionPool {
    pool: Pool,
}

impl ConnectionPool {
    pub async fn new(cfg: Configuration) -> Result<ConnectionPool> {
        let manager =
            bb8_postgres::PostgresConnectionManager::new(cfg.build()?, tokio_postgres::tls::NoTls);
        let pool: Pool = bb8::Pool::builder()
            .max_size(configuration::POOL_SIZE)
            .build(manager)
            .await?;
        if environment::in_development() {
            println!("Connected to database.");
        }
        Ok(ConnectionPool { pool })
    }
    pub async fn client(&self) -> Result<client::Client<'_>> {
        Ok(client::Client::new(self.pool.get().await?))
    }
    pub async fn migrate(&self, path: &str) -> Result<()> {
        let mut sql_files = files::by_extension(path, SQL_EXTENSION);
        sql_files.sort();
        let client = self.client().await?;
        for file_path in sql_files.iter() {
            let sql = fs::read_to_string(file_path)?;
            client.batch(&sql).await?;
        }
        Ok(())
    }
}

#[async_trait]
pub trait ConnectionPoolTrait<'a: 'b, 'b, T: Client<'a, 'b>>: Clone + Send + Sync {
    type T;
    async fn client(&'a self) -> Result<Self::T>;
    async fn migrate(&self, path: &str) -> Result<()>;
}

#[async_trait]
impl<'a: 'b, 'b, T: Client<'a, 'b>> ConnectionPoolTrait<'a, 'b, T> for ConnectionPool {
    type T = client::Client<'a>;
    async fn client(&'a self) -> Result<Self::T> {
        Ok(client::Client::new(self.pool.get().await?))
    }
    async fn migrate(&self, path: &str) -> Result<()> {
        let mut sql_files = files::by_extension(path, SQL_EXTENSION);
        sql_files.sort();
        let client = self.client().await?;
        for file_path in sql_files.iter() {
            let sql = fs::read_to_string(file_path)?;
            client.batch(&sql).await?;
        }
        Ok(())
    }
}
generics asynchronous rust traits
1个回答
0
投票

我相信这是rust中GAT的一个问题,它还没有完成。根据我的理解,GAT's将提供将trait作为类型参数的能力,但是目前这种行为还在开发中,不支持。

GAT github问题

© www.soinside.com 2019 - 2024. All rights reserved.