Generic type with trait bound as return type

I have this code

#[derive(Debug, Clone)]
struct Foo{}

impl From<i32> for Foo {
    fn from(k:i32) -> Self {
        Foo{}
    }
}

#[derive(Debug, Clone)]
struct Bar{}

impl From<i32> for Bar {
    fn from(k:i32) -> Self {
        Bar{}
    }
}

fn return_val<T: From<i32>>(arg: i32) -> Option<T> {
    if arg == 1{
        let r = Foo::from(arg);
        return Some(r);
    }
    else if arg == 2 {
        let r = Bar::from(arg);
        return Some(r);
    }
    else {
        return None;
    }
}

fn main() {
    let a = return_val::<i32>(0);
    println!("{:?}", a);
    let b = return_val::<i32>(1);
    println!("{:?}", b);
    let c = return_val::<i32>(2);
    println!("{:?}", c);
}

basically Here I want to return a type implementing From<i32> trait from the function return_val . Even though both Foo & Bar types implements From<i32> I get this below

error[E0308]: mismatched types
   --> src/main.rs:26:21
    |
19  | fn return_val<T: From<i32>>(arg: i32) -> Option<T> {
    |               - expected this type parameter
...
26  |         return Some(r);
    |                ---- ^ expected type parameter `T`, found `Bar`
    |                |
    |                arguments to this enum variant are incorrect
    |
    = note: expected type parameter `T`
                       found struct `Bar`

error[E0308]: mismatched types
   --> src/main.rs:22:21
    |
19  | fn return_val<T: From<i32>>(arg: i32) -> Option<T> {
    |               - expected this type parameter
...
22  |         return Some(r);
    |                ---- ^ expected type parameter `T`, found `Foo`
    |                |
    |                arguments to this enum variant are incorrect
    |
    = note: expected type parameter `T`
                       found struct `Foo`

I have even tried using Option<impl From<i32>> as return type. but even that failing with a different error. Could anyone help me understand why these are failing? is dyn trait is the solution in such scenarios?

Rust is statically typed. You cannot conditionally return either Foo or Bar from a function.
If you want to do something like this, you'll need to either

  1. Pass the desired return type as type parameter and return it
  2. Return a trait object

That being said, looking your code, especially at the branch condition that translates an integer to a type, this rather looks like an X/Y problem.
Why would you want to do something like this?
It'd probably be better to encode the type information not with an integer but using Rust's type system.
So, what is your actual goal here?

2 Likes

Or return an enum with one variant for each type that can be returned.

1 Like

Yeah, either probably being the most prominent solution here, but I still think this is an xy problem.