42
votes

In Rust the main function is defined like this:

fn main() {

}

This function does not allow for a return value though. Why would a language not allow for a return value and is there a way to return something anyway? Would I be able to safely use the C exit(int) function, or will this cause leaks and whatnot?

5
C’s exit is not good inasmuch as it does not run destructors. The main side-effect this will have is that buffers will not be flushed. e.g. if you have written to stdout or stderr your output may never be written, as they are buffered. - Chris Morgan
It can be more serious than that. For example, in certain situations you might end up being unable to bind to a TCP port that you had bound for a minute or two (until a timeout in the kernel expires). - Chris Morgan
@Mike: that’s system buffers. Where buffering is done in user space (e.g. BufWriter), exit will not flush the buffers. - Chris Morgan
Also this RFC discussion: github.com/rust-lang/rfcs/issues/1176. - ArtemGr

5 Answers

39
votes

As of Rust 1.26, main can return a Result:

use std::fs::File;

fn main() -> Result<(), std::io::Error> {
    let f = File::open("bar.txt")?;

    Ok(())
}

The returned error code in this case is 1 in case of an error. With File::open("bar.txt").expect("file not found"); instead, an error value of 101 is returned (at least on my machine).

Also, if you want to return a more generic error, use:

use std::error::Error;
...

fn main() -> Result<(), Box<dyn Error>> {
   ...
}
23
votes

std::process::exit(code: i32) is the way to exit with a code.


Rust does it this way so that there is a consistent explicit interface for returning a value from a program, wherever it is set from. If main starts a series of tasks then any of these can set the return value, even if main has exited.

Rust does have a way to write a main function that returns a value, however it is normally abstracted within stdlib. See the documentation on writing an executable without stdlib for details.

5
votes

The reddit thread on this has a "why" explanation:

Rust certainly could be designed to do this. It used to, in fact.

But because of the task model Rust uses, the fn main task could start a bunch of other tasks and then exit! But one of those other tasks may want to set the OS exit code after main has gone away.

Calling set_exit_status is explicit, easy, and doesn't require you to always put a 0 at the bottom of main when you otherwise don't care.

5
votes

As was noted by others, std::process::exit(code: i32) is the way to go here

More information about why is given in RFC 1011: Process Exit. Discussion about the RFC is in the pull request of the RFC.

-1
votes

You can set the return value with std::os::set_exit_status.