Been trying to write a function just to do this.
fn main() -> Result<i32, i32> {
let clargs: Vec<String> = env::args().collect();
// validate command line arguments
if clargs.len() != 3 {
// clargs[0] is the name of the executable
print_usage(&clargs[0]);
return Err(1);
}
return Ok(0);
}
fn print_usage(exe_name: &String) {
eprintln!("Usage: {exe_name} <word_file> <hash_sha1>");
}
I also tried this.
fn main() -> Result<(), std::io::Error> {
let clargs: Vec<String> = env::args().collect();
// validate command line arguments
if clargs.len() != 3 {
// clargs[0] is the name of the shacker1 executable
print_usage(&clargs[0]);
return Err("error: invalid number of arguments.");
}
return Ok(());
}
fn print_usage(exe_name: &String) {
eprintln!("Usage: {exe_name} <word_file> <hash_sha1>");
}
But I can't figure out how to transform a string in to an error. Can't find it in the docs. Can't find examples.
How does one return anything like what I'm doing here?
There are a couple possible ways to go about returning a specific error code from a Rust program. One is to return something that implements the Termination
trait. That can be ExitCode
, which represents an exit status; a Result<T, E>
where T
implements Termination
and E
implements Debug
; or one of a few other things.
So, the simplest way to simply return a status code is this:
use std::env;
use std::process::ExitCode;
fn main() -> ExitCode {
let clargs: Vec<String> = env::args().collect();
// validate command line arguments
if clargs.len() != 3 {
// clargs[0] is the name of the executable
print_usage(&clargs[0]);
return 2.into();
}
0.into()
}
fn print_usage(exe_name: &String) {
eprintln!("Usage: {exe_name} <word_file> <hash_sha1>");
}
ExitCode
implements From<u8>
, so you can simply call .into
on a u8
and that will work. Note that this gives you the most flexibility, because it allows you to return any unsuccessful status you want.
You can also do something like this (only main
is shown):
fn main() -> Result<(), &'static str> {
let clargs: Vec<String> = env::args().collect();
// validate command line arguments
if clargs.len() != 3 {
// clargs[0] is the name of the executable
print_usage(&clargs[0]);
return Err("invalid number of arguments");
}
Ok(())
}
That works because &'static str
implements Debug
. Note that this will not give you as much control over the exit status, which may or may not be a problem.
Finally, you can simply call std::process::exit
. This can be done anywhere, but this shows how you might do it if you want (only main
and do_main
shown):
fn do_main() -> i32 {
let clargs: Vec<String> = env::args().collect();
// validate command line arguments
if clargs.len() != 3 {
// clargs[0] is the name of the executable
print_usage(&clargs[0]);
return 2;
}
0
}
fn main() {
std::process::exit(do_main());
}
Note that i32
doesn't implement Termination
, so you can't use Result<i32, i32>
as the return type. You could use Result<ExitCode, i32>
, but that would print the error i32
, which you probably wouldn't want, so simply returning ExitCode
would be more along the lines of what you're going for.