如何访问 Rust 中的命令行参数?

生锈教程没有解释如何从命令行获取参数。在所有示例中,fn main()只显示了一个空参数列表。

main访问命令行参数的正确方法是什么?

53440 次浏览

可以使用 std::env::argsstd::env::args_os函数访问命令行参数。两个函数都返回参数上的迭代器。前者迭代 String(易于使用) ,但是如果其中一个参数不是有效的 unicode,则会出现恐慌。后者在 OsString上迭代,从不恐慌。

注意迭代器的第一个元素是程序本身的名称(这是所有主要操作系统的约定) ,因此第一个参数实际上是第二个迭代元素。

处理 args结果的一个简单方法是将其转换为 Vec:

use std::env;


fn main() {
let args: Vec<_> = env::args().collect();
if args.len() > 1 {
println!("The first argument is {}", args[1]);
}
}

可以使用整个 标准迭代器工具箱来处理这些参数。例如,只检索第一个参数:

use std::env;


fn main() {
if let Some(arg1) = env::args().nth(1) {
println!("The first argument is {}", arg1);
}
}

您可以在 板条箱上找到用于解析命令行参数的库:

  • Docopt : 您只需编写帮助消息,就可以生成解析代码。
  • 鼓掌 : 您描述了希望使用流畅的 API 解析的选项。比 docopt 更快,并且给你更多的控制权。
  • Getopts : 流行的 C 库的端口。更低级,甚至更多的控制。
  • Structopt : 建立在拍的顶部,它是更符合人体工程学的使用。

什么 Barjak 说适用于字符串,但是如果你需要参数作为一个数字(在本例中是一个 uint) ,你需要像下面这样转换:

fn main() {
let arg : ~[~str] = os::args();
match uint::from_str(arg[1]){
Some(x)=>io::println(fmt!("%u",someFunction(x))),
None=>io::println("I need a real number")
}
}

Rust 在 Getopts 板条箱中具有 getopt样式的 CLI 参数解析。

在0.8/0.9版本中,函数 args ()的正确路径是 ::std::os::args,即:

fn main() {
let args: ~[~str] = ::std::os::args();
println(args[0]);
}

即使是标准的 I/O,Rust 现在似乎仍然相当不稳定,所以这可能很快就会过时。

对于较新的 Rust 版本(Rust > 0.10.11) ,数组语法不起作用。您必须使用 get 方法。

数组语法在夜间工作,所以你可以在 getter 和数组索引之间选择。

use std::os;


fn main() {
let args = os::args();
println!("{}", args.get(1));
}


// Compile
rustc args.rs && ./args hello-world // returns hello-world

自从2013年5月 卡尔文的回答以来,Rust 已经发生了演变。现在可以用 as_slice()解析命令行参数:

use std::os;


fn seen_arg(x: uint)
{
println!("you passed me {}", x);
}
fn main() {
let args = os::args();
let args = args.as_slice();
let nitems = {
if args.len() == 2 {
from_str::<uint>(args[1].as_slice()).unwrap()
} else {
10000
}
};


seen_arg(nitems);
}

Docopt 也可用于 Rust,它从用法字符串为您生成一个解析器。作为 Rust 的一个好处,宏可以用来自动生成 struct 并执行基于类型的解码:

docopt!(Args, "
Usage: cp [-a] SOURCE DEST
cp [-a] SOURCE... DIR


Options:
-a, --archive  Copy everything.
")

你可以这样争论:

let args: Args = Args::docopt().decode().unwrap_or_else(|e| e.exit());

README 和 文件有大量完整的工作示例。

免责声明: 我是本图书馆的作者之一。

生锈的书“没有 stdlib”章节介绍了如何访问命令行参数(另一种方式)。

// Entry point for this program
#[start]
fn start(_argc: isize, _argv: *const *const u8) -> isize {
0
}

现在,这个例子也有 #![no_std],我认为这意味着通常情况下,std 库将拥有二进制文件的真实入口点,并调用一个名为 main()的全局函数。另一个选项是“禁用 main垫片”与 #![no_main]。如果我没记错的话,这是在告诉编译器你正在完全控制你的程序是如何启动的。

#![no_std]
#![no_main]


#[no_mangle] // ensure that this symbol is called `main` in the output
pub extern fn main(argc: isize, argv: *const *const u8) -> isize {
0
}

如果您只想读取命令行参数,那么我不认为这是一种“好”的做事方式。其他答案中提到的 std::os模块似乎是一种更好的方法。我发布这个答案是为了完成。

铁锈又变了。不推荐使用 os::args(),而支持使用 std::args()。但是 std::args()不是一个数组,它返回一个 迭代器。可以迭代命令行参数,但不能使用下标访问它们。

Http://doc.rust-lang.org/std/env/fn.args.html

如果您希望命令行参数作为字符串的向量,那么现在可以这样做:

use std::env;
...
let args: Vec<String> = env::args().map(|s| s.into_string().unwrap()).collect();

锈——学会接受改变带来的痛苦。

对我来说,getopts 总是觉得太低级,而 docopt.rs 太神奇了。 我想要一些明确和直接的,仍然提供所有的功能,如果我需要他们。

这就是 鼓掌派上用场的地方。
感觉有点像 Python 中的 argparse。 下面是一个例子:

let matches = App::new("myapp")
.version("1.0")
.author("Kevin K. <kbknapp@gmail.com>")
.about("Does awesome things")
.arg(Arg::with_name("CONFIG")
.short("c")
.long("config")
.help("Sets a custom config file")
.takes_value(true))
.arg(Arg::with_name("INPUT")
.help("Sets the input file to use")
.required(true)
.index(1))
.arg(Arg::with_name("debug")
.short("d")
.multiple(true)
.help("Sets the level of debugging information"))
.get_matches();

你可以这样访问你的参数:

println!("Using input file: {}", matches.value_of("INPUT").unwrap());


// Gets a value for config if supplied by user, or defaults to "default.conf"
let config = matches.value_of("CONFIG").unwrap_or("default.conf");
println!("Value for config: {}", config);

(抄自 正式文件)

还可以查看 structopt:

extern crate structopt;
#[macro_use]
extern crate structopt_derive;


use structopt::StructOpt;


#[derive(StructOpt, Debug)]
#[structopt(name = "example", about = "An example of StructOpt usage.")]
struct Opt {
/// A flag, true if used in the command line.
#[structopt(short = "d", long = "debug", help = "Activate debug mode")]
debug: bool,


/// An argument of type float, with a default value.
#[structopt(short = "s", long = "speed", help = "Set speed", default_value = "42")]
speed: f64,


/// Needed parameter, the first on the command line.
#[structopt(help = "Input file")]
input: String,


/// An optional parameter, will be `None` if not present on the
/// command line.
#[structopt(help = "Output file, stdout if not present")]
output: Option<String>,
}


fn main() {
let opt = Opt::from_args();
println!("{:?}", opt);
}

Https://github.com/texitoi/structopt

如果要在命令行参数上迭代:

use std::env::{args,Args};


fn main() {
let mut args:Args=args();
// args.nth(0) cannot borrow as mutable. that is why  let mut args
// nth return an element of iterator
let first=args.nth(1).unwrap();
// iterator has next method. we want to get the first element of next iterator. NOT args.nth(2)
// chars returns an iterator
let operator=args.nth(0).unwrap().chars().next().unwrap();
let second=args.nth(0).unwrap();
}

如果您想直接访问非 h 参数:

fn get_nth_arg(n:usize)->String{
std::env::args().nth(n).unwrap()
}

我个人不喜欢在没有必要的小型项目中使用库,而且解析 Rust 中的命令行参数非常简单:

fn main() {
let config: String;


let mut args = env::args().skip(1);
while let Some(arg) = args.next() {
match &arg[..] {
"-h" | "--help" => help(),
"--version" => {
println!("{} {}", prog().unwrap_or_default(), VERSION);
}
"-q" | "--quiet" => {
println!("Quiet mode is not supported yet.");
}
"-v" | "--verbose" => {
println!("Verbose mode is not supported yet.");
}
"-c" | "--config" => {
if let Some(arg_config) = args.next() {
config = arg_config;
} else {
panic!("No value specified for parameter --config.");
}
}
_ => {
if arg.starts_with('-') {
println!("Unkown argument {}", arg);
} else {
println!("Unkown positional argument {}", arg);
}
}
}
}
}

为了处理非字符串参数,可以使用 String: : parse ()方法尝试将给定的字符串解析为指定的类型:

"-s" | "--size" => {
if let Some(arg_size) = arg_it.next() {
size = arg_size
.parse::<usize>()
.expect("Size argument expects an integer value.");
} else {
panic!("No value specified for parameter size.");
}
}

如果您希望处理等号(=)而不是空格的值,您可以在 match子句上包含以下代码,然后匹配键值:

let (key, value) = match arg.contains('=') {
true => {
let str_vec: Vec<&str> = arg.split('=').collect();
(String::from(str_vec[0]), Some(String::from(str_vec[1])))
},
false => {
(arg, None)
}
};