#Trait bounds with generics

20 messages · Page 1 of 1 (latest)

turbid falcon
#

So i have this code:
https://play.rust-lang.org/?version=stable&mode=debug&edition=2021&gist=bee1747f8a1333d012f5ceb0ddb04b86
I'm trying to get a feel for how to use trait bounds and generics especially when something is not defined in the same mod.
I tried to look at the rustbook example of a trait bound, but I don't see the mistake right now.
I'm not sure why line 54/55 dont work.

Those are the lines in question and the error i get

    pub fn getDoSomething<T>() -> DoSomething<T>  where T:Repository{
        DoSomething::new(RealRepo::new())
    }

It says:

error[E0308]: mismatched types
  --> src/main.rs:55:26
   |
54 |     pub fn getDoSomething<T>() -> DoSomething<T>  where T:Repository{
   |                           - this type parameter
55 |         DoSomething::new(RealRepo::new())
   |         ---------------- ^^^^^^^^^^^^^^^ expected type parameter `T`, found struct `RealRepo`
   |         |
   |         arguments to this function are incorrect
   |
   = note: expected type parameter `T`
                      found struct `RealRepo<'_>`
note: associated function defined here
  --> src/main.rs:23:16
   |
23 |         pub fn new(repository: T) -> Self {
   |                ^^^ -------------

Could you help me please?

#

If i had to guess, i would say that line 23/24 are at fault here. I guess even though the implementation should work with something that implements a trait, the construction or at least the parameter there cant be a struct that implements a trait. That would probably require a trait object right?

jolly forge
#

when you write get_do_something<T>() -> DoSomething<T>, the caller of the function gets to decide what type T is, not you.

#

so your code would have to work for any T that the user can decide, not just the RealRepo you chose

#

If you only want to return DoSomething<RealRepo>, you should write that instead

turbid falcon
#

thanks for your answer! But i am still quiet confused:
the book used this

pub struct Screen<T: Draw> {
    pub components: Vec<T>,
}

impl<T> Screen<T>
where
    T: Draw,
{
    pub fn run(&self) {
        for component in self.components.iter() {
            component.draw();
        }
    }
}

as an example. This seems like only something that could take anything that implements the trait draw...

I would love to be able to let the caller decide what T is, but i get another error then, that i have to specify what T is in line 54

#

if i write the code above like that

    pub fn get_do_something<T>() -> DoSomething<T>{
        DoSomething::new(RealRepo::new())
    }

i get this error

error[E0277]: the trait bound `T: Repository` is not satisfied
  --> src/main.rs:54:37
   |
54 |     pub fn get_do_something<T>() -> DoSomething<T>{
   |                                     ^^^^^^^^^^^^^^ the trait `Repository` is not implemented for `T`
   |
note: required by a bound in `DoSomething`
  --> src/main.rs:7:31
   |
7  |     pub struct DoSomething<T: Repository> {
   |                               ^^^^^^^^^^ required by this bound in `DoSomething`
help: consider restricting type parameter `T`
   |
54 |     pub fn get_do_something<T: business::Repository>() -> DoSomething<T>{
   |                              ++++++++++++++++++++++

#

and following that suggestion will just bring me back to what it was

jolly forge
#

So in that example from the book, it is saying that components is holding a Vec<T>, where T is one specific type the user picked that implements the Draw trait. The run() method then does the only thing it can do with such a generic type, which is to call the .draw() method that we know exists on T since it must implement Draw

jolly forge
#

as you aren't returning T, you are returning one specific type you picked always

turbid falcon
#

oh wow.. i wrote DoSomething<T> where T:RealRepo and didnt notice that that is not the same

#

thank you so much

#

this got me so confused

#

and at that point it needs a static lifetime right? Can i somehow prevent that? (even though I'm pretty sure a static lifetime makes sense there)

jolly forge
#

the only lifetime that makes sense in this context is a 'static one, as you aren't passing any other reference that you could be borrowing from

#

though speaking of lifetimes, you probably want to change RealRepo to store a String instead of a &str, that way it has ownership of firstname

#

most the time you should prefer your structs to have ownership instead of holding a reference

turbid falcon
#

that's a really nice hint, thank you 🙂
now i need to figure out the myriad of errors that came from fixing this one 😄

#

for one I would need to specify the type in the first few lines now. Which I probably can't 😅
edit:
I kept a generic parameter after the pub fn get_do_something() .. which is stupid.. and it's a stupid name for a function, sorry for that.
Huge thanks for the quick help again 🙂