< 返回版块

php-lsys 发表于 2021-11-03 14:44

函数内的泛型无法推导该怎么解决?

trait IDB {}
struct IMY{}
impl IDB for IMY{}
struct Pool1<DB:IDB>{
    _db:DB
}
trait Encode1<DB:IDB> {}
struct Query<DB:IDB>{
    _a:Pool1<DB>
}
trait SS<DB: IDB> {
    fn bind1<T: Encode1<DB> >(&self, _: T);
}

struct  BB{}

impl Encode1<IMY> for BB {}
struct  BB1{}
impl Encode1<IMY> for BB1 {}

impl <DB: IDB> SS<DB> for Query<DB> {
    fn bind1<T:Encode1<DB> >(&self, _: T)  {
        
    }
}

fn main() {    
    // let res =Query{_a:Pool1{_db:IMY{}}};
    // res.bind1(BB{});
    // res.bind1(BB1{});
    pub fn myexec<DB:IDB>(pool:Pool1<DB>)
    {
        let res =Query{_a:pool};
        res.bind1(BB{});
        res.bind1(BB1{});
    }
    myexec::<IMY>(Pool1{_db:IMY{}});

}
rror[E0277]: the trait bound `BB: Encode1<DB>` is not satisfied
  --> src\main.rs:36:19
   |
36 |         res.bind1(BB{});
   |             ----- ^^^^ the trait `Encode1<DB>` is not implemented for `BB`
   |             |
   |             required by a bound introduced by this call
   |
help: consider introducing a `where` bound, but there might be an alternative better way to express this requirement
   |
33 |     pub fn myexec<DB:IDB>(pool:Pool1<DB>) where BB: Encode1<DB>
   |                                           +++++++++++++++++++++

error[E0277]: the trait bound `BB1: Encode1<DB>` is not satisfied
  --> src\main.rs:37:19
   |
37 |         res.bind1(BB1{});
   |             ----- ^^^^^ the trait `Encode1<DB>` is not implemented for `BB1`
   |             |
   |             required by a bound introduced by this call
   |
help: consider introducing a `where` bound, but there might be an alternative better way to express this requirement
   |
33 |     pub fn myexec<DB:IDB>(pool:Pool1<DB>) where BB1: Encode1<DB>
   |                                           ++++++++++++++++++++++

评论区

写评论
作者 php-lsys 2021-11-03 20:26

而且我打算把execute_by_pk 写出通用的函数。 如果别人依赖我的crate的话, 他新增的类型将得不到支持。 因为没包含进execute_by_pk的where之后。 感觉包装出来的函数就废了。

--
👇
Grobycn: 这问题原因是泛型约束不足,假设 bind(1) 这里是 i32, i32实现了 Encode<_, MySql>, Encode<_, Postgres> 等等一系列特性,但并不是通用的 Encode<_, DB>。 泛型是无穷的,而实现是有限的。因此总有可能有一种类型 MyDB, i32 并没有实现 Encode<_, MyDB>。 因此在 where 语句后面加上约束 i32: Encode<_, DB> 可以通过编译,当然还要约束一下生命周期。

作者 php-lsys 2021-11-03 20:23

这样加约束的话会挺恐怖。等于要把所有的绑定的类型都在where后加一遍。

--
👇
Grobycn: 这问题原因是泛型约束不足,假设 bind(1) 这里是 i32, i32实现了 Encode<_, MySql>, Encode<_, Postgres> 等等一系列特性,但并不是通用的 Encode<_, DB>。 泛型是无穷的,而实现是有限的。因此总有可能有一种类型 MyDB, i32 并没有实现 Encode<_, MyDB>。 因此在 where 语句后面加上约束 i32: Encode<_, DB> 可以通过编译,当然还要约束一下生命周期。

Grobycn 2021-11-03 19:34

这问题原因是泛型约束不足,假设 bind(1) 这里是 i32, i32实现了 Encode<_, MySql>, Encode<_, Postgres> 等等一系列特性,但并不是通用的 Encode<_, DB>。 泛型是无穷的,而实现是有限的。因此总有可能有一种类型 MyDB, i32 并没有实现 Encode<_, MyDB>。 因此在 where 语句后面加上约束 i32: Encode<_, DB> 可以通过编译,当然还要约束一下生命周期。

作者 php-lsys 2021-11-03 17:38
[dependencies]
actix-web = "~4.0.0-beta.8"
sqlx = {version = "~0.5.5",features = [ "mysql","runtime-tokio-native-tls","offline"]}

--
👇
php-lsys:


use sqlx::{Arguments, Database, Executor, IntoArguments, MySql, Pool, database::HasArguments, query::Query};

pub async fn test_db()->sqlx::Pool<sqlx::MySql>{
    use std::str::FromStr;
    let database_url = "mysql://root:@127.0.0.1/test";
    let option =sqlx::mysql::MySqlConnectOptions::from_str(&database_url)
        .unwrap();
    sqlx::pool::PoolOptions::<sqlx::MySql>::new()
        .max_connections(5)
        .connect_with(
            option.to_owned()
        )
        .await
        .unwrap()
}

pub fn bind_values<'q,DB>(
    mut res:Query<'q,DB,<DB as HasArguments<'q>>::Arguments>,
) -> Query<'q,DB,<DB as HasArguments<'q>>::Arguments> 
where DB:Database{
    res = res.bind(1);
    //              ---- ^ the trait `Encode<'_, DB>` is not implemented for `{integer}`
    res
}

pub async fn execute_by_pk<'c,DB>(pool:&'c Pool<DB>)
    ->Result<<DB as Database>::QueryResult,sqlx::Error>
    where 
        DB:Database,
        for<'q>
            <DB as HasArguments<'q>>::Arguments:
                Arguments<'q>+IntoArguments<'q,DB>,
        &'c Pool<DB>: Executor<'c, Database = DB>
{
    let b="select 1".to_string();
    let mut res = sqlx::query::<DB>(b.as_str());
    res = res.bind(&1);
    res.execute(pool).await
}


#[actix_web::main]
async fn main() {
    let pool=test_db().await;
    let _res=execute_by_pk::<MySql>(&pool).await;
}


作者 php-lsys 2021-11-03 17:36

use sqlx::{Arguments, Database, Executor, IntoArguments, MySql, Pool, database::HasArguments, query::Query};

pub async fn test_db()->sqlx::Pool<sqlx::MySql>{
    use std::str::FromStr;
    let database_url = "mysql://root:@127.0.0.1/test";
    let option =sqlx::mysql::MySqlConnectOptions::from_str(&database_url)
        .unwrap();
    sqlx::pool::PoolOptions::<sqlx::MySql>::new()
        .max_connections(5)
        .connect_with(
            option.to_owned()
        )
        .await
        .unwrap()
}

pub fn bind_values<'q,DB>(
    mut res:Query<'q,DB,<DB as HasArguments<'q>>::Arguments>,
) -> Query<'q,DB,<DB as HasArguments<'q>>::Arguments> 
where DB:Database{
    res = res.bind(1);
    //              ---- ^ the trait `Encode<'_, DB>` is not implemented for `{integer}`
    res
}

pub async fn execute_by_pk<'c,DB>(pool:&'c Pool<DB>)
    ->Result<<DB as Database>::QueryResult,sqlx::Error>
    where 
        DB:Database,
        for<'q>
            <DB as HasArguments<'q>>::Arguments:
                Arguments<'q>+IntoArguments<'q,DB>,
        &'c Pool<DB>: Executor<'c, Database = DB>
{
    let b="select 1".to_string();
    let mut res = sqlx::query::<DB>(b.as_str());
    res = res.bind(&1);
    res.execute(pool).await
}


#[actix_web::main]
async fn main() {
    let pool=test_db().await;
    let _res=execute_by_pk::<MySql>(&pool).await;
}


作者 php-lsys 2021-11-03 17:30

trait SS<DB: IDB> { fn bind1<T: Encode1>(&self, _: T); } 这个是外部crate定义的.我改不了. 谢谢大佬帮忙

--
👇
苦瓜小仔: 那就去修改函数定义啊,我又不知道你想干嘛。

trait Encode1<DB: IDB> {}
struct BB {}
impl Encode1<IMY> for BB {}
struct BB1 {}
impl Encode1<IMY> for BB1 {}

trait SS<DB: IDB> {
    fn bind1<T: Encode1<IMY>>(&self, _: T);
}

impl<DB: IDB> SS<DB> for Query<DB> {
    fn bind1<T: Encode1<IMY>>(&self, _: T) {}
}

https://play.rust-lang.org/?version=nightly&mode=debug&edition=2021&gist=57eb6f230b41a1313d20b180f538e2af

--
👇
php-lsys: 就是不能单一实现啊 能单一对泛型实现我就不用定义这个泛型了

--
👇
苦瓜小仔: 根据 fn bind1<T: Encode1> 的函数定义,你需要对 BB 和 BB1 实现泛型,即:

trait Encode1<DB: IDB> {}
struct BB {}
impl<DB: IDB> Encode1<DB> for BB {}
struct BB1 {}
impl<DB: IDB> Encode1<DB> for BB1 {}

https://play.rust-lang.org/?version=stable&mode=debug&edition=2021&gist=7551857cfe7187665700ea2df79a9073

苦瓜小仔 2021-11-03 17:19

那就去修改函数定义啊,我又不知道你想干嘛。

trait Encode1<DB: IDB> {}
struct BB {}
impl Encode1<IMY> for BB {}
struct BB1 {}
impl Encode1<IMY> for BB1 {}

trait SS<DB: IDB> {
    fn bind1<T: Encode1<IMY>>(&self, _: T);
}

impl<DB: IDB> SS<DB> for Query<DB> {
    fn bind1<T: Encode1<IMY>>(&self, _: T) {}
}

https://play.rust-lang.org/?version=nightly&mode=debug&edition=2021&gist=57eb6f230b41a1313d20b180f538e2af

--
👇
php-lsys: 就是不能单一实现啊 能单一对泛型实现我就不用定义这个泛型了

--
👇
苦瓜小仔: 根据 fn bind1<T: Encode1> 的函数定义,你需要对 BB 和 BB1 实现泛型,即:

trait Encode1<DB: IDB> {}
struct BB {}
impl<DB: IDB> Encode1<DB> for BB {}
struct BB1 {}
impl<DB: IDB> Encode1<DB> for BB1 {}

https://play.rust-lang.org/?version=stable&mode=debug&edition=2021&gist=7551857cfe7187665700ea2df79a9073

作者 php-lsys 2021-11-03 17:09

就是不能单一实现啊 能单一对泛型实现我就不用定义这个泛型了

--
👇
苦瓜小仔: 根据 fn bind1<T: Encode1> 的函数定义,你需要对 BB 和 BB1 实现泛型,即:

trait Encode1<DB: IDB> {}
struct BB {}
impl<DB: IDB> Encode1<DB> for BB {}
struct BB1 {}
impl<DB: IDB> Encode1<DB> for BB1 {}

https://play.rust-lang.org/?version=stable&mode=debug&edition=2021&gist=7551857cfe7187665700ea2df79a9073

苦瓜小仔 2021-11-03 16:24

根据 fn bind1<T: Encode1> 的函数定义,你需要对 BB 和 BB1 实现泛型,即:

trait Encode1<DB: IDB> {}
struct BB {}
impl<DB: IDB> Encode1<DB> for BB {}
struct BB1 {}
impl<DB: IDB> Encode1<DB> for BB1 {}

https://play.rust-lang.org/?version=stable&mode=debug&edition=2021&gist=7551857cfe7187665700ea2df79a9073

1 共 9 条评论, 1 页