A Rust function with no explicit return type is equivalent to one whose return type is explicitly marked ()
(pronounced "unit"). This is the equivalent to void
in the C++-family of languages. So
fn example() {
loop {}
}
is equivalent to
fn example() -> () {
loop {}
}
It effectively "ignores" the return value. So if we have a function bar()
which returns i32
, then
fn foo() -> i32 {
bar()
}
is a function returning the result of bar
, while
fn foo() {
bar()
}
is a function which calls bar
and then throws away its return value.
!
(pronounced "never") is a bit special in Rust. A value of type !
can be assigned to a variable of any type. On the other hand, ()
is an ordinary type. So if we called the !
version of our example
function in, say, one arm of a match
statement, then it would happily coexist with whatever the return type of the match
is.
match foo() {
Some(x) => 0,
None => example(),
}
example
will agree with this match
, since it will loop forever (or panic) and never return. But the ()
version of example
will fail to compile, since ()
and i32
are not the same type.
In summary, if you can explicitly mark a function as returning !
, then you should do so. A return type of !
is always better than one of ()
, since the former can be converted to the latter.