Rust教程没有解释如何从命令行获取参数。在所有示例中,fn main()
都只显示为空参数列表。
从main
访问命令行参数的正确方法是什么?
std::env::args
或std::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() {
// we use nth(1) for the first argument because
// nth(0) traditionally corresponds to the binary path
if let Some(arg1) = env::args().nth(1) {
println!("The first argument is {}", arg1);
}
}
Docopt同样适用于Rust,它可以根据使用字符串为您生成解析器。作为Rust的额外奖励,可以使用宏自动生成结构体并进行基于类型的解码:
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和文档可获得许多完整的工作示例。
免责声明:我是这个库的作者之一。
对我来说,getopts 总是感觉太底层了,而 docopt.rs 又有太多的魔法。
我想要的是一些明确而简单的东西,但如果需要的话仍然提供所有功能。
这就是 clap-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();
你可以这样访问你的参数:You can access your parameters like so:
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);
(从官方文档复制)
在较小的项目中,如果没有必要,我个人不喜欢使用库,而在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);
}
}
}
}
}
"-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)
}
};
::std::os::args
,即:fn main() {
let args: ~[~str] = ::std::os::args();
println(args[0]);
}
同时也请查看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);
}
os::args()
,而是使用std::args()
。但是std::args()
并不是数组,它返回的是一个迭代器。你可以迭代处理命令行参数,但不能使用下标来访问它们。use std::env;
...
let args: Vec<String> = env::args().map(|s| s.into_string().unwrap()).collect();
Rust - 学会拥抱变化的痛苦。
(Rust是一种编程语言,其特点是内存安全和高性能)env::args().collect()
。 - tshepang《Rust书籍》中的“无标准库”章节介绍了如何访问命令行参数(另一种方式)。
// Entry point for this program
#[start]
fn start(_argc: isize, _argv: *const *const u8) -> isize {
0
}
#![no_std]
。我认为这意味着通常std库会为您的二进制文件提供真正的入口点并调用一个名为main()
的全局函数。另一种选择是使用#![no_main]
来“禁用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
模块似乎是一种更好的方式。我发表这个答案是为了完整性。
如果您想要迭代命令行参数:
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();
}
如果你想直接访问第n个参数:
fn get_nth_arg(n:usize)->String{
std::env::args().nth(n).unwrap()
}