How could i return a trait using generic skill?

pub trait Contract {
    fn f1<B>(b: B);
    fn f2<C: Contract>() -> C;
}

pub struct BBB;

impl Contract for BBB {
    fn f1<B>(b: B) {
        println!("---> f1()");
    }
    
    fn f2<C: Contract>() -> C {
        let b = BBB{};
        println!("---> f2()");
        return b;
    }
}

Play Online

ErrorInfo:

Compiling playground v0.0.1 (/playground)
error[E0308]: mismatched types
  --> src/lib.rs:16:16
   |
13 |     fn f2<C: Contract>() -> C {
   |                             - expected `C` because of return type
...
16 |         return b;
   |                ^ expected type parameter, found struct `BBB`
   |
   = note: expected type `C`
              found type `BBB`

error: aborting due to previous error

Hi,

Today, I encounted some troublesome problems when i handle trai-return situation.
I wanted to return a trait, but it can not be returned by Box<Contract>, for:

method `f1` has generic type parameters

So, i attemped to use generic, but it not worked yet. so sad.

In f2<C> the C is chosen by the caller of the function.

In f2() -> impl C the C is chosen by the function itself, but this syntax is not supported in traits.

In your case Box<dyn Contract> is required.

1 Like

I tried to change trait signature like this:

pub trait Contract {
    fn f1<B>(&self, b: B);
    fn f2(&self) -> Box<Contract>;
}

error info:

Compiling playground v0.0.1 (/playground)
error[E0038]: the trait `Contract` cannot be made into an object
 --> src/lib.rs:3:5
  |
3 |     fn f2(&self) -> Box<Contract>;
  |     ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ the trait `Contract` cannot be made into an object
  |
  = note: method `f1` has generic type parameters

I guess this trait usage maybe obey trait-object safe rule.

fn f2(&self) -> Box<dyn Contract>

don't forget dyn

You can also use associated types if you want to avoid the box

1 Like
pub
trait Contract {
    fn f1<B> (b: B);

    type F2RetValue : Contract;
    fn f2 () -> Self::F2RetValue;
}

pub
struct BBB;

impl Contract for BBB {
    fn f1<B> (b: B)
    {
        println!("---> f1()");
    }
    
    type F2RetValue = BBB;
    fn f2 () -> Self::F2RetValue
    {
        let b = BBB;
        println!("---> f2()");
        b
    }
}
2 Likes

In my mind, Box has no difference with Box ? right?

Yes, but the without dyn syntax is deprecated because it is easy to confuse with normal types. Adding dyn makes it clear that you working with trait objects.

1 Like

Thanks, Now i am so clear about this subtle difference. :beers: