babla34
babla34

Reputation: 25

Multiple return types from same function signature Rust

I have a function in Rust that takes in two arguments and returns a Result. It is defined below as follows.

fn calculate_density(a: String, with_correction: bool) -> Result<u64, String>;

The thing is I want to modify my method signature in such a way that the return type for a successful result depends on the argument with_correction.

For example id with_correction is set to true I send back u64. If false I want to send a String.

I have tried to do this with a tuple where the successful result is a tuple of Options and they are set at run time depending on with_correction

fn calculate_density(a: String, with_correction: bool) -> Result<(Option<u64>, Option<String>), String>;

But this seems like an overkill. Are there better ways to achieve this?

Upvotes: 0

Views: 787

Answers (1)

cafce25
cafce25

Reputation: 27356

If your output depends on a single bool input the first thing you should consider is splitting it up into 2 functions:

fn calculate_density(a: String) -> Result<String, String> {
    // do stuff
}
fn calculate_density_with_correction(a: String) -> Result<u64, String> {
    calculate_density(a).map(|density| density.parse::<u64>().unwrap_or_default())
}

If you really, really want to have multiple outputs with different types you could use an enum like this:

enum Output {
    WithCorrection(u64),
    WithoutCorrection(String),
}
fn calculate_density(a: String, with_correction: bool) -> Result<Output, String> {
    // …
    let uncorrected = String::from("uncorrected_value");
    if with_correction {
        let corrected = correct(uncorrected);
        Ok(Output::WithCorrection(corrected))
    } else {
        Ok(Output::WithoutCorrection(uncorrected))
    }
}

or if you don't want to write a custom enum use Either:

use either::Either;

fn calculate_density(a: String, with_correction: bool) -> Result<Either<u64, String>, String> {
    // …
    let uncorrected = String::from("uncorrected_value");
    if with_correction {
        let corrected = correct(uncorrected);
        Ok(Either::Left(corrected))
    } else {
        Ok(Either::Right(uncorrected))
    }
}

Upvotes: 6

Related Questions