Rust generic return type

Hello,

I have a function called function. When given true it should return 5, else "This is a string".

Here is a code example:

fn main() {
    println!("{}", function(true));
}

fn function<T>(something: bool) -> T {
    if something {
        return 5;
    } else {
        return "This is a string";
    }
}

When running this, I get the following error:

error[E0308]: mismatched types
 --> src/main.rs:7:16
  |
5 | fn function<T>(something: bool) -> T {
  |             - this type parameter  - expected `T` because of return type
6 |     if something {
7 |         return 5;
  |                ^ expected type parameter `T`, found integer
  |
  = note: expected type parameter `T`
                       found type `{integer}`

What am I doing wrong and how can I fix this program?

Thank you! Jeroen

In Rust, the type of every value must be known at compile time, so this program cannot work as written. enums are designed for situations like this: They define a number of variants, and the particular variant can be decided at runtime. The downside of this is that, whenever you want to use the enum, you need to describe what happens for each variant separately:

(untested)

use std::fmt::Display;

fn main() {
    println!("{}", function(true));
}

enum StrOrInt {
    Str(&’static str),
    Int(i32)
}

impl Display for StrOrInt {
    fn fmt(&self, f: &mut Formatter<'_>) -> Result<(), std::fmt::Error> {
        match Self {
            StrOrInt::Str(s) => s.fmt(f),
            StrOrInt::Int(x) => x.fmt(f)
        }
    }
}

fn function(something: bool) -> StrOrInt {
    if something {
        return StrOrInt::Int(5);
    } else {
        return StrOrInt::Str("This is a string");
    }
}

If all you want to do with the result is display it, the either crate defines an enum that forwards a bunch of common trait implementations, including Display. Or you could do the formatting inside function and return a String.

3 Likes

What you need to further understand is that generic type parameters are chosen by the caller of the generic function, and they are chosen at compile time. So the function implementation itself doesn't decide what type is substituted for the parameter, and it has to work with every such possible type. After all, the point of generics is that "this function should work properly with many (sets of) types given to it", but that's not what you are doing here.

In your case, the implementation wants to decide the type of the return value, what's more, it wants to do that dynamically. This means that generics are not suited for accomplishing this in any meaningful way.

7 Likes

Rust's strong static typing doesn't allow you to do this. Also if generic type isn't infered or used as an argument's type, you need to specify it while calling: name::<T>(arg).

You may try to use trait objects

fn function(something: bool) -> &'static dyn core::fmt::Display {
    if something {
        &5
    } else {
        &"This is a string"
    }
}

fn main() {
    println!("{}", function(true));
}

This topic was automatically closed 90 days after the last reply. We invite you to open a new topic if you have further questions or comments.