5

I'm trying to do the rustlings course and I don't understand the error I'm getting for the following code:

pub fn bigger(a: i32, b: i32) -> i32 {
    if a > b {
        a
    }
    b
}

Error:

error[E0308]: mismatched types
 --> exercises/if/if1.rs:7:9
  |
6 | /     if a > b {
7 | |         a
  | |         ^ expected `()`, found `i32`
8 | |     }
  | |_____- expected this to be `()`
  |
help: you might have meant to return this value
  |
7 |         return a;
  |         ^^^^^^  ^

if I add the return, it does work but shouldn't the above also work? If I use an if-else it works also:

pub fn bigger(a: i32, b: i32) -> i32 {
    if a > b {
        a
    } else {
        b
    }
}
mkrieger1
  • 19,194
  • 5
  • 54
  • 65
Charlie
  • 176
  • 11
  • 1
    https://stackoverflow.com/questions/30812469/returning-a-value-from-within-an-if-statement-has-a-mismatched-types-error should answer your question. The if without an else is evaluated as an expression returning () (i.e. void) – Giovanni Oct 20 '21 at 07:41
  • Does this answer your question? [Returning a value from within an if statement has a "mismatched types" error](https://stackoverflow.com/questions/30812469/returning-a-value-from-within-an-if-statement-has-a-mismatched-types-error) – Herohtar Oct 20 '21 at 15:43
  • Does this answer your question? [Result and if/else/return statements E0308 error](https://stackoverflow.com/questions/51049717/result-and-if-else-return-statements-e0308-error) – mkrieger1 Dec 24 '21 at 23:55

1 Answers1

10

In rust only the last expression is taken as return value.

In your case:

if a > b {
    a
}

and:

b

are expressions themselves, so which one should it return? In fact if expressions without an else clause return () in Rust (that is why you get the conflict in types). For more reference refer to this question.

Meanwhile:

if a > b {
    a
} else {
    b
}

is a single expression, whose branches are single expressions too (a and b). So it is clear that it should return what the inner return of the if expressions does.

Also, you can use a return statement in the if expression to help the compiler realize what to do in the first case (From @Cerberus' comments: return x is an expression, too - it just evaluates to never and so can be used everywhere without type mismatch.):

pub fn bigger(a: i32, b: i32) -> i32 {
    if a > b {
        return a;
    }
    b
}

Just the last b expression would be used as final return (other returns are statements, not expressions).

TylerH
  • 20,799
  • 66
  • 75
  • 101
Netwave
  • 40,134
  • 6
  • 50
  • 93
  • 1
    Small nitpick: `return x` is an expression, too - it just evaluates to `never` and so can be used everywhere without type mismatch. – Cerberus Oct 20 '21 at 09:07
  • @Cerberus The type of the `return` expression does not matter here, since the trailing semicolon changes the type of an expression to `()`. You can use an expression of an arbitrary type in that place as long as you add the semicolon. The only special thing about the `return` expression being of type `!` is that you could omit the semicolon and it would still compile, but please don't do that. :) – Sven Marnach Oct 20 '21 at 09:21
  • 2
    To be even more precise, the mere _presence_ of the return expression changes the type of the entire block to `!`, so you could use an expression of an arbitrary type after the return expression without a trailing semicolon, and it would still compile. – Sven Marnach Oct 20 '21 at 09:24