简体   繁体   English

通用 function 和 async_trait 的困难

[英]difficulty with generic function and async_trait

I am trying to implement the following trait:我正在尝试实现以下特征:

#[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<()>;
}

when I try to compile the code I get the following error:当我尝试编译代码时,出现以下错误:

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)

It looks like a conflict/issue with async_trait, but I'm a bit stumped as to how to approach a solution.它看起来像是 async_trait 的冲突/问题,但我对如何解决问题感到有些困惑。 My motivation is to create a mockable interface for my database connection.我的动机是为我的数据库连接创建一个可模拟的接口。 I found a forum that says it may be a compiler bug here , hoping that's not the case.我发现一个论坛说这可能是编译器错误希望不是这样。

the following is the full file/code以下是完整的文件/代码

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(())
    }
}

I believe this is an issue with GAT's in rust, which are not yet complete.我相信这是 rust 中 GAT 的问题,尚未完成。 As I understand it GAT's would provide the ability to have a trait as a type parameter, however currently this behavior is in development/not supported.据我了解,GAT 将提供将特征作为类型参数的能力,但是目前这种行为正在开发中/不受支持。

GAT github issue GAT github 问题

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM