rust 如何在多个文件/模块中实现相同的trait,避免“trait实现冲突”错误?

6psbrbz9  于 2022-11-12  发布在  其他
关注(0)|答案(2)|浏览(160)

在Golang中,我可以定义如下接口:

type DBRepo interface {
  PlayerByID(id uint64) (*domain.Player, error)
  TeamByID(id uint64) (*domain.Team, error)
  // many others

我可以使用不同的文件来实现它们:

// file: real_db.go
type RealDB struct {
  db *realDB
}

// file: player.go
func (r RealDB) PlayerByID(id uint64) (*domain.Player, error) {
  return r.db... // get from DB
}

// file: team.go
func (r RealDB) TeamByID(id uint64) (*domain.Team, error) {
  return r.db... // get from DB
}

// many others (files and methods)

我不能理解如何做同样的 rust :


# [async_trait::async_trait]

pub trait DBRepo: Send + Sync {
    async fn player_by_id(&self, id: i64) -> Result<()>;
    async fn team_by_id(&self, id: i64) -> Result<()>;
}

但是如果我在不同的文件中写下面的代码(也是不同的mods):

// file: player.rs

# [async_trait::async_trait]

impl DBRepo for Repo {
    async fn player_by_id(&self, id: i64) -> Result<()> {
        Ok(()) // get from DB
    }
}

// file: team.rs

# [async_trait::async_trait]

impl DBRepo for Repo {
    async fn team_by_id(&self, id: i64) -> Result<()> {
        Ok(()) // get from DB
    }
}

我从编译器中得到:

error[E0119]: conflicting implementations of trait `DBRepo` for type `Repo`
--> src\team.rs:22:1
   |
22 | impl DBRepo for Repo {
   | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ conflicting implementation for `Repo`
   |
  ::: src\player.rs:22:1
   |
22 | impl DBRepo for Repo {
   | ----------------------------------- first implementation here

For more information about this error, try `rustc --explain E0119`.

我该如何解决这个问题?

我需要在特征DBRepo上使用所有方法,我无法将其拆分为多个特征。

laik7k3q

laik7k3q1#

您可以将DBRepo特性拆分为多个特性,并将DBRepo特性定义为需要所有其他特性。


# [async_trait::async_trait]

pub trait DBRepoPlayer: Send + Sync {
    async fn player_by_id(&self, id: i64) -> Result<()>;
}

# [async_trait::async_trait]

pub trait DBRepoTeam: Send + Sync {
    async fn team_by_id(&self, id: i64) -> Result<()>;
}
pub trait DBRepo: DBRepoPlayer + DBRepoTeam {}
impl<T: DBRepoPlayer + DBRepoTeam> DBRepo for T {}

然后在类型上实现子特征:

// file: player.rs

# [async_trait::async_trait]

impl DBRepoPlayer for Repo {
    async fn player_by_id(&self, id: i64) -> Result<()> {
        Ok(()) // get from DB
    }
}

// file: team.rs

# [async_trait::async_trait]

impl DBRepoTeam for Repo {
    async fn team_by_id(&self, id: i64) -> Result<()> {
        Ok(()) // get from DB
    }
}

我知道你说过不要分割特性,但是在rust中多次实现相同的特性是不可能的,部分特性实现也是不可能的。

jum4pzuy

jum4pzuy2#

你不能在rust中部分实现一个trait,如果你有Repo类型,并且想实现DBRepo,那么整个trait实现必须在impl块中定义。
例如,即使不跨文件拆分,此示例也将失败:

struct A;

trait Foo {
    fn fn_1();
    fn fn_2();
}

impl Foo for A {
    fn fn_1() {}
}

impl Foo for A {
    fn fn_2() {}
}

这会失败,并显示错误“conflicting implementation for A“,正如您在多个文件的示例中看到的那样。即使在同一个文件中,这也不起作用。
如果你只是这样做:

struct A;

trait Foo {
    fn fn_1();
    fn fn_2();
}

impl Foo for A {
    fn fn_1() {}
}

您将看到您也会得到一个编译器错误:'实现”中缺少fn_2
在不将trait拆分为多个trait的情况下,实现这一点的唯一方法是将整个trait impl包含在一个文件中:


# [async_trait::async_trait]

impl DBRepo for Repo {
    async fn player_by_id(&self, id: i64) -> Result<()> {
        Ok(()) // get from DB
    }

    async fn team_by_id(&self, id: i64) -> Result<()> {
        Ok(()) // get from DB
    }
}

相关问题