8

I am applying the polymorphism solution in Rust to my problem. I would like to use this solution with Box<_> as it seems the most straight and simple, but it doesn't work.

#[derive(Clone, Copy)]
pub struct NewPost;

#[derive(Clone, Copy)]
pub struct Post;

#[derive(Clone, Copy)]
pub struct PgConnection;

#[derive(Clone, Copy)]
pub struct DBPost;

pub trait DBAdapter {
    fn create(self, post: NewPost) -> Post;
    fn read(self) -> Vec<Post>;
}

impl DBPost {
    // DATABASE classes
    pub fn establish_connection(self) -> PgConnection {
        unimplemented!()
    }
}

impl DBAdapter for DBPost {
    fn create(self, _post: NewPost) -> Post {
        unimplemented!()
    }

    fn read(self) -> Vec<Post> {
        unimplemented!()
    }
}

struct GetPostsCase {
    db: Box<dyn DBAdapter>,
}

impl GetPostsCase {
    pub fn new(db: Box<dyn DBAdapter>) -> GetPostsCase {
        GetPostsCase { db: db }
    }

    pub fn run(&self) -> Vec<Post> {
        let result = self.db.read();
        result
    }
}

The error is:

error[E0161]: cannot move a value of type dyn DBAdapter: the size of dyn DBAdapter cannot be statically determined
  --> src/lib.rs:45:22
   |
45 |         let result = self.db.read();
   |                      ^^^^^^^

error[E0507]: cannot move out of `*self.db` which is behind a shared reference
  --> src/lib.rs:45:22
   |
45 |         let result = self.db.read();
   |                      ^^^^^^^ move occurs because `*self.db` has type `dyn DBAdapter`, which does not implement the `Copy` trait
Shepmaster
  • 388,571
  • 95
  • 1,107
  • 1,366
carlos.baez
  • 1,063
  • 2
  • 11
  • 31
  • 1
    Why do your `DBAdapter` `read `method` take a `self` instead of a `&mut self` ? This involves moving the db adapter, and is probably useless. – Denys Séguret Aug 26 '19 at 15:34
  • 2
    Please try to to build a [MCVE]. Too many aspects are missing and might make us guess wrong about what you really try to do. It's also possible dynamic polymorphism isn't really the best solution here. – Denys Séguret Aug 26 '19 at 15:37
  • Thanks, I appreciate any advice to reduce this example. In fact, I tried to do the minimal example but I don't know how to remove more not necessary code. About the solution, sorry but I would be against, I am asking how to apply dynamic polymorphism not if it is the best solution. – carlos.baez Aug 26 '19 at 15:44
  • 3
    Since you were asking about how to produce a MRE, here's my copy-paste comment: It would make it easier for us to help you if you try to reproduce your error on the [Rust Playground](https://play.rust-lang.org) if possible, otherwise in a brand new Cargo project, then [edit] your question to include the additional info. There are [Rust-specific MRE tips](//stackoverflow.com/tags/rust/info) you can use to reduce your original code for posting here. – Shepmaster Aug 26 '19 at 15:50

1 Answers1

9

Your read method takes the (unsized) value instead of taking a reference (whose size is always the same).

You can solve the problem by changing the contract of DBAdapter

from

fn read(self) -> Vec<Post> {

to

fn read(&self) -> Vec<Post> {
//      ^--- added the ampersand

(depending on your implementation you might need &mut)

Denys Séguret
  • 372,613
  • 87
  • 782
  • 758