163

Rust 教程没有解释如何从命令行获取参数。fn main()在所有示例中仅以空参数列表显示。

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

4

12 回答 12

183

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

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

处理结果的一种简单方法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);
    }
}

您可以在crates.io上找到用于解析命令行参数的库:

  • docopt:您只需编写帮助消息,并为您生成解析代码。
  • clap:您使用流利的 API 描述要解析的选项。比 docopt 更快,并为您提供更多控制。
  • getopts:流行的 C 库的端口。更低级别,甚至更多控制。
  • structopt:建立在 clap 之上,使用起来更加符合人体工程学。
于 2013-03-25T18:16:47.837 回答
24

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());

自述文件和文档有大量完整的工作示例。

免责声明:我是这个库的作者之一。

于 2014-10-23T02:22:00.343 回答
13

Rust在getopts crategetopt中有-style CLI 参数解析。

于 2013-07-08T21:24:13.300 回答
10

对我来说,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();

您可以像这样访问您的参数:

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);

(复制自官方文档

于 2016-01-09T12:33:05.827 回答
4

从 0.8/0.9 版开始,函数 args() 的正确路径是::std::os::args,即:

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

看起来,即使是标准 I/O,Rust 现在仍然很不稳定,所以这可能很快就会过时。

于 2013-12-05T21:46:44.997 回答
3

锈又变了。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();

Rust - 学会拥抱变化的痛苦。

于 2015-02-05T23:47:53.970 回答
3

另请查看 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

于 2017-10-09T14:30:34.420 回答
2

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")
    }
}
于 2013-05-11T17:46:01.480 回答
1

Rust 书“No 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模块似乎是一种更好的做事方式。为了完成,我发布了这个答案。

于 2014-11-10T14:43:23.117 回答
1

自 2013 年 5 月Calvin 的回答以来,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);
}
于 2014-10-17T13:36:21.363 回答
1

从较新的 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
于 2014-08-11T17:19:08.017 回答
0

如果要迭代命令行参数:

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()
}
于 2022-02-24T23:14:55.307 回答