Rust书中的I/O project example建议克隆命令行args:
fn main() {
let args: Vec<String> = env::args().collect();
let config = parse_config(&args);
// ...
}
struct Config {
query: String,
filename: String,
}
fn parse_config(args: &[String]) -> Config {
let query = args[1].clone();
let filename = args[2].clone();
Config {
query, filename
}
}
我想将值移到Config
结构中以避免复制。
我尝试移动切片:
fn parse_config(args: [String]) -> Config
但得到了错误:
the trait `std::marker::Sized` is not implemented for `[std::string::String]`
这是有道理的,因为它现在正在读取一个未大小的数组。接下来我尝试了泛型:
fn parse_config<T: std::ops::Index<usize, Output=String> + Sized>(args: T) -> Config
出现错误:
cannot move out of indexed content
这也是有道理的,因为它会将矢量保留在invalid state中。我可以移动矢量:
fn parse_config(mut args: Vec<String>) -> Config {
let query = args.remove(1);
// ...
但现在该功能与特定容器Vector
绑定。
我如何编写一个使用向量并允许我移出其内容的函数,同时仍然保留函数的通用性质?
答案 0 :(得分:3)
答案是使用消费迭代器:
...
let config = parse_config(args.into_iter());
...
fn parse_config<T: Iterator<Item=String>>(mut args: T) -> Config {
let query = args.nth(1).expect("First arg none");
let filename = args.nth(0).expect("Second arg none");
...
}
请注意,nth
函数正在推进和使用迭代器,因此,而不是在2
处索引的第二个参数,现在是一个迭代,即0
。