Skip to content
Select theme

How to return a value from a function

Short answer: the last expression in a function body is its return value, and it must not end in a semicolon. a + b returns the sum. a + b; throws the sum away, the body’s value becomes (), and the function no longer compiles against its -> i32. Write return a + b; if you prefer, but the semicolon-free tail expression is what you’ll see in most Rust code.

In src/main.rs:

cargo build prints:

error[E0308]: mismatched types
--> src/main.rs:1:27
|
1 | fn add(a: i32, b: i32) -> i32 {
| --- ^^^ expected `i32`, found `()`
| |
| implicitly returns `()` as its body has no tail or `return` expression
2 | a + b;
| - help: remove this semicolon to return this value
For more information about this error, try `rustc --explain E0308`.

The caret lands on the return type, not on the semicolon, and the note in the middle is the whole explanation: the body “implicitly returns () as its body has no tail or return expression”. With the semicolon, a + b; is a statement — it computes a number and drops it. The last thing in the body is now a statement, statements have no value, so the body is () and () is not i32. The help line at the bottom is the fix.

cargo run prints:

5

a + b is an expression: it produces a value. Sitting last in the body, it becomes the tail expression, and the function returns it. Nothing else is needed — no return, no temporary.

The semicolon is the whole difference between the two versions. a + b and a + b; both build an i32; one keeps it as the body’s value and the other drops it. The compiler complains only because the declared return type disagrees with what’s left.

12
0

return hands a value back straight away and stops the function. The semicolon after it is fine — there is nothing left to evaluate. The tail expression still supplies the value when control reaches the end of the body, which is why width * height needs no return in front of it. Use return to leave before the last line; writing it on the last line as well is legal, though longer.

A block is an expression too: { } has the value of its last line, and a semicolon throws that value away in the same way:

error[E0308]: mismatched types
--> src/main.rs:3:22
|
3 | let total: i32 = {
| ______________________^
4 | | let shipping = 2;
5 | | price * 10 + shipping;
| | - help: remove this semicolon to return this value
6 | | };
| |_____^ expected `i32`, found `()`
For more information about this error, try `rustc --explain E0308`.

Same error, same help text, same cause. Take the semicolon off and the block hands its value to total:

32

let shipping = 2; keeps its semicolon, because nothing wants the value of 2. The line that closes the block doesn’t, because that value is the block’s result.

Both errors so far were a value being thrown away. This one is the reverse — a value with no return type to receive it:

error[E0308]: mismatched types
--> src/main.rs:2:5
|
1 | fn shout(message: &str) {
| - help: try adding a return type: `-> &str`
2 | message
| ^^^^^^^ expected `()`, found `&str`
For more information about this error, try `rustc --explain E0308`.

A function with no -> returns (), so message has nowhere to go. The compiler’s own suggestion is the fix: give the function a -> &str. If a function returns nothing on purpose, though, the tail expression and the statement are interchangeable — fn main() { println!("hi") } compiles and prints hi.