简体   繁体   English

如果没有拍手给定位置参数,如何使用STDIN?

[英]How do I use STDIN if no positional arguments are given with clap?

I have a clap App like this: 我有一个鼓掌的App像这样:

let m = App::new("test")
    .arg(
        Arg::with_name("INPUT")
            .help("a string to be frobbed")
            .multiple(true),
    )
    .get_matches();

I want to read the arguments as an iterable of strings if there are any myapp str1 str2 str3 but if not, to act as a filter and read an iterable of lines from stdin cat afile | myapp 如果有myapp str1 str2 str3 ,我想将参数作为字符串的可迭代形式读取,但如果没有,则充当过滤器并从stdin cat afile | myapp读取行的可迭代形式cat afile | myapp cat afile | myapp . cat afile | myapp This is my attempt: 这是我的尝试:

let stdin = io::stdin();
let strings: Box<Iterator<Item = String>> = if m.is_present("INPUT") {
    Box::new(m.values_of("INPUT").unwrap().map(|ln| ln.to_string()))
} else {
    Box::new(stdin.lock().lines().map(|ln| ln.unwrap()))
};

for string in strings {
    frob(string)
}

I believe that, since I am just requiring the Iterator trait, a Box<Iterator<Item = String>> is the only way to go. 我相信,由于我只需要Iterator特性,所以Box<Iterator<Item = String>>是唯一的方法。 Is that correct? 那是对的吗?

There is rarely an "only way to go", and this case is no different. 很少有“唯一的出路”,这种情况也不例外。 One alternative approach would be to use static dispatch instead of dynamic dispatch. 一种替代方法是使用静态调度而不是动态调度。

Your main processing code needs an iterator of strings as input. 您的主要处理代码需要一个字符串迭代器作为输入。 So you could define a processing function like this: 因此,您可以定义如下处理函数:

fn process<I: IntoIterator<Item = String>>(strings: I) {
    for string in strings {
        frob(string);
    }
}

The invocation of this code could look like this: 这段代码的调用看起来像这样:

match m.values_of("INPUT") {
    Some(values) => process(values.map(|ln| ln.to_string())),
    None => process(io::stdin().lock().lines().map(|ln| ln.unwrap())),
}

The compiler will emit two different versions of process() , one for each iterator type. 编译器将发出两个不同版本的process() ,每种迭代器类型一个。 Each version statically calls the iterator functions it is compiled for, and there is only a single dispatch to the right function in the match statement. 每个版本都会静态调用为其编译的迭代器函数,并且match语句中只有一个调度程序可以分配给正确的函数。

(I probably got some details wrong here, but you get the idea.) (我可能在这里弄错了一些细节,但您明白了。)

Your version, on the other hand, uses the type Box<dyn Iterator<Item = String>> , so the iterators will be allocated on the heap, and there will be a dynamic dispatch each time next() is called on the iterator. 另一方面,您的版本使用Box<dyn Iterator<Item = String>> ,因此迭代器将分配在堆上,并且每次在迭代器上调用next()时,都会有一个动态调度。 Which is probably fine. 这可能很好。

There are certainly more ways of structuring the code and dispatching between the two different kinds of input, eg using the Either type from the either crate, or simply writing two different for loops for the two cases. 当然,还有更多的方法来构造代码并在两种不同类型的输入之间进行分配,例如,使用either包装箱中的Either类型,或针对两种情况仅编写两种不同的for循环。 Which one to choose depends on tradeoffs with other requirements of your code, your performance requirements and your personal preferences. 选择哪一个取决于代码的其他要求,性能要求和个人偏好之间的权衡。

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM