使用rust从命令行读取一个整数



我有以下代码来创建长度为n+1的字符串,其中n作为命令行参数传递:

let args: Vec<String> = env::args().collect();
let min_no_of_bytes =  &args[2].parse::<u64>();
let no_of_times_to_repeat =  min_no_of_bytes as usize;
let mut inputtext='0'.to_string().repeat(no_of_times_to_repeat);

但是我在编译过程中得到以下错误:

error[E0606]: casting `&Result<u64, ParseIntError>` as `usize` is invalid
--> src/main.rs:33:17
|
33 |     let temp =  min_no_of_bytes as usize;
|                 ^^^^^^^^^^^^^^^^^^^^^^^^
|
= help: cast through a raw pointer first

请建议。谢谢。

原代码中有几个问题没有处理。

  • args不保证有第二个参数,因此&args[2]可能会panic
  • &args[2]处的字符串不保证是可解析的数字,因此parse返回Result,这可能携带错误。

在Rust中通常不鼓励直接访问数组。这当然是可能的,但它可能会引起恐慌,而且速度很慢。因此,如果要访问数组,通常使用迭代器.get()函数。


处理所有错误

首先,我建议在我们使它变得更漂亮之前处理所有的错误。如果您避免直接访问数组和unwrap:

,那么rust编译器应该强制您这样做。
use std::env;
fn main() {
let args: Vec<String> = env::args().collect();
let arg = match args.get(2) {
Some(val) => val,
None => {
println!("Not enough arguments provided!");
return;
}
};
let min_no_of_bytes = match arg.parse::<u64>() {
Ok(val) => val,
Err(e) => {
println!("Unable to parse number from argument: {}", e);
return;
}
};
let no_of_times_to_repeat = min_no_of_bytes as usize;
let inputtext = '0'.to_string().repeat(no_of_times_to_repeat);
println!("{}", inputtext);
}

使用:cargo run -- bla 3运行此程序打印000


设置正确的错误处理

如果你意识到我们现在有println!(...error)return紧挨着彼此。相反,我们可以直接从main返回一个错误来组合这两个操作。Rust会自动打印错误。

为了接受任何错误类型,可以使用Result<(), Box<dyn Error>>类型或像anyway这样的包装类型来完成。

我将在这里提供anyhow解决方案,因为我认为通常使用包装器库而不是直接使用Box<dyn Error>会更好。

use anyhow::{anyhow, Result};
use std::env;
fn main() -> Result<()> {
let args: Vec<String> = env::args().collect();
let arg = args
.get(2)
.ok_or(anyhow!("Not enough arguments provided!"))?;
let min_no_of_bytes = arg.parse::<u64>()?;
let no_of_times_to_repeat = min_no_of_bytes as usize;
let inputtext = '0'.to_string().repeat(no_of_times_to_repeat);
println!("{}", inputtext);
Ok(())
}

注意这里的?操作符,这是一种快速表示"如果这是Err值,则从函数返回它,否则将值展开"的方式。基本上是安全的、错误传播的.unwrap()版本。


使用合适的命令行解析库

我不会在这里深入讨论细节,但是如果您的项目代码略多于10行,您很快就会发现手动编写参数解析非常乏味。

有几个库使这个过程非常容易。在写这篇文章的时候,我推荐的是clap:

use clap::Parser;
/// A program that does things
#[derive(Parser, Debug)]
#[clap(version, about)]
struct Args {
/// Minimum number of bytes
#[clap(short)]
min_no_of_bytes: u64,
}
fn main() {
let args = Args::parse();
let no_of_times_to_repeat = args.min_no_of_bytes as usize;
let inputtext = '0'.to_string().repeat(no_of_times_to_repeat);
println!("{}", inputtext);
}

这需要你的Cargo.toml中的clap = { version = "3.1", features = ["derive"] }

使用cargo run -- -m 3运行它会得到000

很酷的副作用是您可以免费获得帮助消息:

cargo run -- -h

my-program 0.1.0
A program that does things
USAGE:
my-program.exe -m <MIN_NO_OF_BYTES>
OPTIONS:
-h, --help                  Print help information
-m <MIN_NO_OF_BYTES>        Minimum number of bytes
-V, --version               Print version information

以下操作有效:

let args: Vec<String> = env::args().collect();
let min_no_of_bytes = *(&args[2].parse::<usize>().unwrap());
let mut inputtext='0'.to_string().repeat(no_of_times_to_repeat);

相关内容

  • 没有找到相关文章

最新更新