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.
The semicolon that returns nothing
Section titled “The semicolon that returns nothing”In src/main.rs:
fn add(a: i32, b: i32) -> i32 { a + b;}
fn main() { println!("{}", add(2, 3));}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` expression2 | 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.
Drop the semicolon
Section titled “Drop the semicolon”fn add(a: i32, b: i32) -> i32 { a + b}
fn main() { println!("{}", add(2, 3));}cargo run prints:
5a + 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.
return leaves early
Section titled “return leaves early”fn area(width: i32, height: i32) -> i32 { if width <= 0 || height <= 0 { return 0; } width * height}
fn main() { println!("{}", area(3, 4)); println!("{}", area(3, 0));}120return 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.
The rule isn’t about functions
Section titled “The rule isn’t about functions”A block is an expression too: { } has the value of its last line, and a semicolon throws that value away
in the same way:
fn main() { let price = 3; let total: i32 = { let shipping = 2; price * 10 + shipping; }; println!("{total}");}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 value6 | | }; | |_____^ 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:
fn main() { let price = 3; let total: i32 = { let shipping = 2; price * 10 + shipping }; println!("{total}");}32let 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.
The same error the other way round
Section titled “The same error the other way round”Both errors so far were a value being thrown away. This one is the reverse — a value with no return type to receive it:
fn shout(message: &str) { message}
fn main() { shout("hello");}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.
Related
Section titled “Related”- The bits that trip everyone up — the rest of this chapter
- Compiler errors — how to read a diagnostic, then one page per error code
- Next in this chapter: why both branches of an
ifhave to agree on a type