Open-Source Internship opportunity by OpenGenus for programmers. Apply now.
Rust has multiple built-in ways to terminate the program, and every method has specific behavior whenever it's called. We're going to see how different functions in Rust (which we use to exit the program) act and how to use them.
Note that the article contains direct links to the
rust-playground
for you to try the code.
Contents
1. Using exit()
function
std::process::exit()
This function returns nothing and terminates the program by passing the provided exit code to the OS.
And it will not call any destructors, which means you'll need to destroy
everything by yourself before you exit the program using this function.
So, a better way to use exit()
is to call it when you're sure that there are no destructors available.
And one way to do this is to have some different function run as a main() function, which returns an exit code or a Result<T, E>
and accordingly pass the exit code to exit()
function, inside your main() function.
use std::process::exit;
fn fake_main() -> i32 {
// Let's say our program fails
// So, we return one to the OS
1
}
fn main() {
let exit_code = fake_main();
exit(exit_code);
}
2. Using abort()
function
std::process::abort()
Same as the exit()
function, the abort()
function returns nothing and shutdowns the program immediately after being called, which also means that as the exit() it's not going to run any remaining destructors.
Therefore this function should be used when you know that there are no destructors left to run.
Unlike the exit()
function, abort()
shutdowns with signal SIGABRT
because of which your shell will tell you that the program has "Aborted"
Example code:
fn main() {
println!("random");
print!("Print that will execute but not print");
std::process::abort();
println!("Print that will not execute.");
}
why 3rd line is executing but still is not printing, because by default rust refreshes stdout with every newline, and print!()
does not print any newline character.
If you want 3rd line to print, then add
use std::io::{stdout, Write};
at the beginning of the code and then add
stdout().flush();
just above std::process::abort()
and then it should print.
For better understanding put the \n
character somewhere in the 3rd line in Example code without applying above mentioned changes.
print!("Print\n that will execute but not print");
// ^---- something like this.
3. Making program panic to terminate
There are also many ways of making your program panic in Rust the simplest one is to use panic!()
macro or you can also use the following ones:
assert!()
macro.expect()
method.unwrap()
method- Returning
Err(_)
in main - some macro that are wrap around panic!
unreachable!()
unimplemented!()
todo!()
Let's look at some of these.
3.1 panic!()
macro
Unlike exit()
and abort()
, panic!()
does run all destructors and then only terminates the program.
panic!()
can also take a message that will display in stderr, and it is also capable of backtracing the error.
fn main() {
print!("This program only panics");
panic!("Panicking...");
}
Note that unlike abort() this program prints the 2nd line, that's because
abort()
does not empties the io Buffer.
3.2 assert!()
macro
assert()
takes a boolean value, So one can provide a condition that evaluates to a boolean value.
If the given condition evaluates to true
the program will do nothing and will continue.
But if the given condition evaluates to false
then assert will behave like the panic does.
And just like panic, assert is also capable of printing formatted messages to stderr.
use std::io::Read;
fn main() {
println!("Input [a-z]:");
let input = &mut [0];
std::io::stdin().read(input).expect("fail");
assert!(
(input[0] as u8) >= 97 && (input[0] as u8) <= 122,
"input = {}, is not between a-z",
input[0]
);
print!("It's {}", input[0] as char);
}
3.3 Returning Err(_)
in main
By default main returns ()
(empty tuple) but we can also make main return Result<(), E>
, and now if we return Error
the program will terminate with error and will print on stderr.
Example Code:
use std::error::Error;
fn main() -> Result<(), Box<dyn Error>> {
let a = "9sa";
a.parse::<i32>()?;
Ok(())
}
if a function returns Result<T, E>
then ?
can be used instead of the unwrap()
method, and this will return Result<T, E>
, instead of handling it right away.
4. Using return
in the main function
But let's say you want to exit your program normally and do not require all this jargon well, then you can use return
anywhere in your main
function and it should exit cleanly, without leaving any mess or anything behind.
use std::io::Read;
fn main() {
let input = &mut [0];
std::io::stdin().read(input).expect("fail");
if input[0] == 'a' as u8 {
eprint!("Bad!! Bonk!!");
return;
}
// All code that will not execute if the user gets bonk!! in head.
}
Seems like that rust-playground doesn't take user inputs, So, try this code on your machine, but anyway here's the code.
Pausing the program
There are also multiple ways, available to pause your program in between execution for some time or until the program detects any event from the user.
Using sleep()
One way to pause your program, for some particular time is by using sleep()
which takes Duration
struct as an input.
Example Code:
use std::time::Duration;
use std::thread::sleep;
fn main() {
// you can choose between millis, nanos, micros and secs
// we're creating time for 1 second
let time = Duration::from_secs(1);
// sleep
sleep(time);
}
This program should pause for 1 second and then terminate.
Make the program wait for an event
Any process will pause while it's waiting for an input/event from outside the program, So, we're going to make our program wait until the user presses any key.
And for that, we'll be using a crate termion
that can wait and listen for an event.
Example Code:
use std::io::{stdin, stdout, Write};
use termion::input::TermRead;
use termion::raw::IntoRawMode;
fn pause() {
let mut stdout = stdout().into_raw_mode().unwrap();
write!(stdout, "Press any key to continue...\r\n").unwrap();
stdout.flush().unwrap();
stdin().keys().next();
}
fn main() {
println!("Hello");
// Program will pause here until any event occurs that can be register by `tty`.
pause();
println!("World!");
}
This code does not work on Rust-Playground.
What Rust returns when exiting?
If you have ever written a rust program before, you might know that rust returns ()
(empty tuple) by default for any function, even the main function returns ()
(empty tuple), and if you require you can also return Result<T, E>
from the main function.
But what does function like exit()
or panic()
return when they're run well these functions return !
(never primitive type), which represents that it's returning nothing.
If we look at the function signature of the exit()
function then you'll see that it's returning !
pub fn exit(code: i32) -> !
Well, !
is not something that only gets used as to exit the program, so, if you want to read more you can go to never - Rust